Google Interview Question for Software Engineer / Developers


Country: United States
Interview Type: In-Person




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

The data structure to store the generation tree will have nodes defined as

public class Person {
	String name;
	ArrayList<Person> children = null;
	Person parent1;
	Person parent2;

	public Person(String personName, Person personParent1, Person personParent2) {
		name = personName;
		children = new ArrayList<Person>();
		parent1 = personParent1;
		parent2 = personParent2;
	}
	public Person getParent() { return parent; }
}

For 2 persons to be blood related, perform a Breadth First Traversal with the person as root and the parents as child nodes and store in a ArrayList.
Then for both the persons search is there is a common parent in the ArrayList.
If common parent found then, the persons are related, else not related.

- Anonymous June 15, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

We can use BFS or DFS here. DFS is generally a bit easier to implement.

- galli October 27, 2013 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

Let's call the first generation individuals root.
For each individual in the population, maintain a reference to the list of his/her ancestor roots.
If two individuals share an ancestor roots, then they are blood related (at the very least, they share the blood of their common root ancestor)
If two individuals are blood related, then any root ancestor of their LCA (Lowest Common Ancestor) is a shared ancestor root.

Space: N (population size) * K (roots population size)
Time: K (intersection of two sorted lists of size at most K)

- Anonymous July 06, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

The problem is, K can be quite big. E.g. with 5 generations, all approximately the same size, K = N/5, so space is O(N2).

- galli August 10, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Right, this is a common task of finding "connected components" in graph. And the right data structure to use here is "union-find" that works similarly to what is described.

- Dmitry February 14, 2015 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

it is a graph, because two parents ... depends on the assumption, there can be many solutions.

- Anonymous July 16, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

First anonymous has it right, except I think you can make it more efficient by performing a dual BFS concurrently, and checking at each stage whether the next element to be processed exists in the set of ancestors of the other person:

public class Person {
  Person[] parents;
}

// naming for cousins is: n th cousin m times removed
// where n is the min generations to a common ancestor and m is the number of generations difference between the 2 cousins
// so this is going to be O((2^n+m)+2) which is still more efficient than dfs assuming the num generations in the population is > n+m
public boolean bloodRelated(Person p1, Person p2) {
  // simple search would go down p1's children/grandchildren/etc and see if we find p2
  // then vice versa
  // then worry about cousin style relationships
  // here we'd go up the parent tree on both until we found a common node (or ran out of data)

  // we could take this last approach anyway and it would get us a parent-child match too
  Set<Person> p1Ancestors = new HashSet<Person>();
  Set<Person> p2Ancestors = new HashSet<Person>();

  // so ideally here we're going to do BFS, but we're going to do 2 at once to try to minimise the depth we have to go
  List<Person> p1Discovered = new LinkedList<Person>();
  p1Discovered.add(p1);
  List<Person> p2Discovered = new LinkedList<Person>();
  p2Discovered.add(p2);

  while (!p1Discovered.isEmpty() || !p2Discovered.isEmpty()) {
    Person nextP1 = p1Discovered.remove(0);
    if (nextP1 != null) {
      if (p2Ancestors.contains(nextP1)) {
        return true;
      }

      for (Person parent : nextP1.parents) {
        p1Discovered.add(parent);
      }
      p1Ancestors.add(nextP1);
    }

    Person nextP2 = p2Discovered.remove(0);
    if (nextP2 != null) {
      if (p1Ancestors.contains(nextP2)) {
        return true;
      }

      for (Person parent : nextP2.parents) {
        p2Discovered.add(parent);
      }
      p2Ancestors.add(nextP2);
    }
  }
  return false;
}

- eswddd July 25, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Could you explain the running time and space please? Not quite clear.

- Anonymous September 17, 2013 | Flag
Comment hidden because of low score. Click to expand.
1
of 1 vote

This is actually a "connected components" problem. The "family tee" is actually a DAG and If two persons belong to the same connected component they are blood relatives.

- Anonymous December 21, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 2 vote

Just rephrased problem of finding common ancestor of two nodes in a tree (an easy version, since there is parent pointer). Don't believe that Google asks such an easy questions

- gevorgk June 18, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

It's a forest, not a tree. Two families may be not related to each other (think about the Starks and the Lannisters ;-)

- Anonymous July 06, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

Since we have the liberty of making the data structure , I will go like this

struct {
	node *par1;
	node *par2;
	int magicnumber;
} node;

par1,par2 are obvious. While filling in the data , who is child of whom etc, you leave magicnumber as 0;
No lets say you get n queries for siblings or not.

for(i=0;i<n;i++)
{
	input(node1,node2);
	findsiblingsornot(node1,node2,i);
}

in findsiblingsornot() i serves as the query number or the magic number. Do a BFS/DFS using node1 as you like and fill magicnumber=querynumber in nodes you meet;
Next try to do BFS/DFS with node2 and if you get any node with magicnumer=i , you are done :)

Space here is just the space required to create DS. (if you still are considering extra space then its O(n). Time is O(N) too.

You dont need to worry about clearing up after your calls to the function.
Next time you call, you call with bigger magic number.

Now the only question that remains, is how would you solve maps with circles created by people like jamie and cersie ;) Just kiding :D it wouldnt be a circle as the graph is directional :D

- Hill Billy August 26, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

In the worstcase wont the root of the tree be the "LCA (least common ancestor)" of any 2 nodes in the tree? Wouldn't that mean that 2 people are ALWAYS related somehow?

- shrikar July 03, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

Ignoring human cloning, you need two parents to make a baby.

- noisebar September 15, 2013 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Since we have the liberty of making the data structure , I will go like this


struct {
node *par1;
node *par2;
int magicnumber;
} node;
par1,par2 are obvious. While filling in the data , who is child of whom etc, you leave magicnumber as 0;
No lets say you get n queries for siblings or not.


for(i=0;i<n;i++)
{
input(node1,node2);
findsiblingsornot(node1,node2,i);
}
in findsiblingsornot() i serves as the query number or the magic number. Do a BFS/DFS using node1 as you like and fill magicnumber=querynumber in nodes you meet;
Next try to do BFS/DFS with node2 and if you get any node with magicnumer=i , you are done :)

Space here is just the space required to create DS. (if you still are considering extra space then its O(n). Time is O(N) too.

You dont need to worry about clearing up after your calls to the function.
Next time you call, you call with bigger magic number.

- Hill Billy August 26, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Isn't this same as lowest common ancestor?

- Anonymous October 01, 2013 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

public Person {
	String name;
	Person[] bloodRelation; //includes parents, siblings and children.
	@Override
	public boolean equals(Object obj) {
		return this.name.equals(((Person)obj).name);
	}
}

public boolean find (Person p1, Person p2, Set<Person> visited) {
	if(visited.contains(p1)) return false;
	if(p1.equals(p2)) return true;
	visited.add(p1)
	for(Person p : p1.bloodRelation) {
		if(find(p, p2, visited)) return true;
	}
	return false;
}

- mohan.p.upadhyay December 03, 2018 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

Not understanding this suggestion. If you go through parents, siblings, and children, everyone is connected to everyone. So that's not going to work.

- Gilles January 25, 2019 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 votes

In my opinion, bloodRelation should be replaced by parents. The check for p1.equals(p2) should be moved up. And another find command needs to be added to check p2.parents vs p:

public Person {
	String name;
	Person[] parents;
	@Override
	public boolean equals(Object obj) {
		return this.name.equals(((Person)obj).name);
	}
}

public boolean find (Person p1, Person p2, Set<Person> visited) {
	if(p1.equals(p2)) return true;
	if(visited.contains(p1)) return false;
	visited.add(p1)
	for(Person p1Parent : p1.parents) {
		if(find(p1Parent, p2, visited)) return true;

		for(Person p2Parent : p2.parents) {
			if(find(p2Parent, p1Parent, visited)) return true;
		}
	}
	return false;
}

- Gilles January 25, 2019 | Flag
Comment hidden because of low score. Click to expand.
0
of 0 vote

Let's consider the trees starting from the two persons and going through their ancestors. We run a DFS (or BFS) on each and collect their leaf nodes. If there is at least one common leaf node, the two persons are related. This technique reduces the space complexity.

n = number of people
k = number of root ancestors

Time complexity: O(n)
Space complexity: O(k)

- Gilles September 01, 2021 | 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