Google Interview Question for Software Engineers


Country: United States
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
0
of 0 vote

/**
Brute-force solution: Maintain disjoint sets. Compute Euclidean distance between each pair of points and update the parent of each point’s disjoint set (using union by rank and path compression). Time complexity: O(N^2). Space: O(N)
**/

/**Optimal Solution: Use closest points algorithm to solve this problem in O(NlogN) time and O(N) space**/

class Point {
	int x;
	int y;
}

float euclidDistance(Point a, Point b) {}

int find(int[] ds, int idx) {
	Stack<Integer> stack = new Stack<Integer>();
	while (ds[idx] != idx) {
			stack.push(idx);
			idx = ds[idx];
	}
	while (!stack.isEmpty()) {
		int top = stack.pop():
		ds[top] = idx;
	}
	return idx;
}

int pointGroups(Point[] pts, float k) {
	int[] sets = new int[pts.length]//disjoint sets
	for (int i = 0; i < sets.length; i++) {
		sets[i] = i;
	}

	// Sort points by ascending x coordinate
	pts.sort(new Comparator() {
		public int compare(Point first, Point sec) {
			return first.x - sec.x
		}

	}
	
	pointsGroupHelp(pts,0,pts.length - 1, k, ds);
	//Apply path compression and count the total number of groups
	int count = 0;
	boolean[] seenGroup = new boolean[ds.length];
	for (int i = 0; i < ds.length; i++) {
		int p = find(ds,i);
		if (!seenGroup[p]) {
			count++;
			seenGroup[p] = true;
		}
	}
	return count;	
}

void bruteForce(Point[] pts, int start, int end, int[] ds, float k) {
	for (int i = start; i <= end; i++) {

		for (int j = i + 1; j <= end, j++) {
				float d = euclidDistance(pts[i],pts[j]);
				if (d <= k) {

						int minParent = Math.min(ds[i],ds[j]);
						int maxParent = Math.max(ds[i],ds[j]);
						ds[maxParent] = minParent;
				}
		}
	}
}

void pointsGroupHelp(Point[] pts,int start,,int end, float k, int[] ds) {
	if ((end - start + 1) <= 3) {
			bruteForce(pts,start,end,ds,k);
			return;
	}

	int mid = start + (end - start) / 2;
	
	int midX = pts[mid].x; //mid line

	pointsGroupHelp(pts,start,mid,k,ds); // group together all points <= k distance that lie to the left of mid line
	pointsGroupHelp(pts,mid + 1, end, k, ds); // group together all points <= k distance that lie to the right of mid line

	// Find subarray of points that are within <=k units away from midline and group pairs whose distance is <= k
	int stripStart = -1;
	int stripEnd = stripStart;
	for (int i = start; i <= end; i++) {
		if (Math.abs(pts[i].x - midX) <= k) {
			stripStart = stripStart == -1 ? i : stripStart;
			stripEnd = i;
		}
	}
	bruteForce(pts,stripStart,stripEnd,k,ds);
}

- divm01986 December 29, 2019 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

You can not do better than N^2 but some quick optimizations can be done which are also practical during the interview. Like one I am doing below is that list of points is sorted based on their point.x values and comparing each point to the other points from left to right, if point2.x - point1.x > k that there is no need to compare any other values in rest of the list as all the other values will have x values equal to, or bigger than point2.x value. Note: The code below is not tested

List<List<Point>> getSets(Point [] points, int k){
		List<List<Point>> listOfLists = new ArrayList<List<Point>>();
		int [] set = new int[points.length];
		Arrays.fill(set, -1);
		Arrays.sort(points, (a,b)-> a.x - b.x);
		HashMap<Integer, List<Point>> map = new HashMap<>();
		
		for(int i = 0; i < points.length; i++){
			
			for(int j = i + 1; j < points.length; j++){
				if(points[j].x - points[i].x > k)break;
				int distance = getDistance(points[i], points[j]);
				if(distance > k)break;
				int rootOfI = find(set, i);
				int rootOfJ = find(set, j);
				union(set,rootOfI,rootOfJ);
			}
		}
		for(int i = 0; i < set.length; i++){
			int root = find(set, i);
			map.putIfAbsent(root, new ArrayList<Point>());
			map.get(root).add(points[i]);
		}
		for(Map.Entry<Integer, List<Point>> entry: map.entrySet()){
			if(entry.getValue().size() > 1)
				listOfLists.add(entry.getValue());
		}
		return listOfLists;
	}
	int getDistance(Point i, Point j){
		double xVal = Math.pow(Math.abs(i.x - j.x), 2);
		double yVal = Math.pow(Math.abs(i.y - j.y), 2);
		double distance = Math.sqrt(xVal + yVal);
		return (int)distance;
	}
	int find(int [] set, int i){
		if(set[i] < 0)return i;
		return set[i] = find(set,set[i]);
	}
	void union(int [] set, int root1, int root2){
		if(set[root1] < set[root2]){
			set[root2] = root1;
			set[root1]--;
		}else{
			if(set[root1] == set[root2])set[root2]--;
			set[root1] = root2;
		}
	}

- Raminder March 20, 2020 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Ok, why can't it be done in O(NLogN) then. If we get a rectangle shape around the point, then we can just check the x value which is closest to the given point, no ?

- Abhishek June 11, 2020 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Ok, why can't it be done in O(NLogN) then. There is a rectangle formed around the given point. In this rectangle, we can check the point whose x value is closest to the given point, no? If this point has less than K distance, then good, otherwise does not lie in the group.

- Abhishek June 11, 2020 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

public class Point {
    public Double getX() {
        return x;
    }

    public Double getY() {
        return y;
    }

    private final Double x;
    private final Double y;

    public Point(Double x, Double y) {
        this.x = x;
        this.y = y;
    }
}

public class Solution {

    public double distance(Point a, Point b) {
        final double squaredSum = Math.pow(a.getX() - b.getX(), 2) + Math.pow(a.getY() - b.getY(), 2);
        return Math.sqrt(squaredSum);
    }

    public Integer numberOFGroups(List<Point> points, Double k) {
        final Set<Point> notGrouped = new HashSet<>(points);
        final Queue<Point> toVisit = new LinkedList<>();
        Integer groupCounter = 0;

       for (Point p : points) {
           if (notGrouped.contains(p)) {
               notGrouped.remove(p);
               toVisit.add(p);

               while(!toVisit.isEmpty()) {
                   Point visiting = toVisit.poll();

                   for(Iterator<Point> i = notGrouped.iterator(); i.hasNext();) {
                       Point checking = i.next();

                       if (distance(visiting, checking) <= k) {
                           i.remove();
                           toVisit.add(checking);
                       }
                   }
               }

               groupCounter++;
           }
       }

       return groupCounter;
    }
}

- diogonlucena May 02, 2020 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 2 vote

I guess you should use VP-tree or KD or QTree etc. to solve it faster than squared.

- somebody May 17, 2020 | Flag Reply
Comment hidden because of low score. Click to expand.
-1
of 1 vote

As you said O(N^2) answer is pretty straight forward, for each element we check rest of the elements to see if their difference is less than K

One way to get time complexity down to O(N) or O(NlogN) by using a sliding window.

O(N) Time complexity if the input is sorted, else we sort the input and that gives O(NlogN) complexity.

The sliding window will work like below

input: {1,2,5,10} k = 5

We start with the first 2 elements.

i = 0, j = 1

If the difference between the first and last element (j - i) of the slide is <= k, we increase the sliding window to right (j++)
When the difference becomes > k, we increment i (i++)

Every time a new digit gets added to the window, it adds (j-i) number of additional groups to the total.

Example:

input: {1,2,5,10} K = 5
sliding window : [1,2] .  total Groups: 1 [[1,2]]
since 2 - 1 <= 5 ==> j++;
sliding window : [1,2, 5] .  total Groups: 3 [[1,2], [2,5],[1,5]]
since 5 - 1 <= 5 ==> j++;
sliding window : [1,2, 5, 10] .  10-1 > k so we increment i
sliding window : [2, 5, 10] .  10-2 > k so we increment i
sliding window : [5, 10] .  total Groups: 3 [[1,2], [2,5],[1,5], [5,10]]

- Saurabh January 07, 2020 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

In question its mentioned 2d points.. on what basis you will sort your array..What would be the reference ...((1,2),(4,10),(3,11)) cant be sorted like (1,2,3,4, 5) :)

- freak March 22, 2020 | Flag
Comment hidden because of low score. Click to expand.
-1
of 1 vote

Here is approach I could think of. Not fully tested
- sort input on the basis of x coordinate
- use divide and conquer .. as in merge sort
- for each merge step .. <this part is tricky> think how we can merge / form groups in O(n)
... One way could be from left and right array use last and first element and move in left or right away depending on the result of first comparison .. e.g. if xl - xr < K but dist(pl, pr) > K then use y to move in arrays.

- Anonymous December 02, 2020 | Flag Reply
Comment hidden because of low score. Click to expand.
-2
of 2 vote

gjgjg

- khkh December 02, 2019 | Flag Reply
Comment hidden because of low score. Click to expand.
-2
of 2 vote

The idea is to map the 2d points to some sort of fixed reference and only compare where it make sense, instead of comparing each point with all the other point, which makes it a N2 algorithm. So here is my take on this. Divide the entire grid into a chunk of k x k grid squares.
e.g. 1st squre(0,0)(0,k)(k,0)(k,k)
2nd squre (0,k)(k,k)(0,2k)(k.2k)
Then iterate over each point and assign a parent grid
CEIL(i/k) * k, CEIL(j/k)*k

Once we have the squres assigned, iterate over the points which belongs only to adjacent 8 sqaures. Rest will lay out of bound for any 2d points inside this grid. Then like minimum spanning tree algorithm, keep chaining the points.

- Confused Aatma December 03, 2019 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Order : O(N)
However, if all the 2d points are packed with in these 9 squres, then a further division will reduce the number of iteration within the points.

- Confused Aatma December 03, 2019 | Flag
Comment hidden because of low score. Click to expand.
-2
of 2 vote

You can find this in O(N) approach. Find the min from the array and the max from the array.
Now you should have your buckets like this:
bucket1: [min, min + k]
bucket2: [min + k + 1, min + k + 1 + k]
..
bucketN/K: [max - k,max]
Now, you start iteration over the array and find out which bucket the current number belongs to and add it in the corresponding bucket.
When the iteration is over, just check for those buckets whose count of items inserted is greater then 1.

- Abhishek J December 11, 2019 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More