Java – a variant of “looking for a common ancestor”
I recently had a telephone interview It encodes the problem as part of the whole process
A / B | \ C E | | D F \ / G
In this case, given the tree and nodes F and D, the closest common ancestor will be B. the second twist is that the tree is presented as an array The implementation method has the following inputs: public string getca (string [] nodes, string []] parentnodes, string targetnode1, string targetnode2). In this example, nodes = {"g", "F", "e", "d", "C", "B", "a"} and parentnodes = {"F", "d"}, {"e"}, {"B"}, {"C"}, {"a"}, null} basically for nodes [i], the parent node is parentnodes [i]. To tell you the truth, I am completely panicked (already very nervous) And it took a long time to find the answer Although I think this is a recursive solution, I have come up with an iterative solution. As far as I know, it is feasible: I push nodes in the queue, and then rise the first target node and then the second node Once I find a node i have encountered, I think it is the solution (annotated to clear things)
public String getCA(String[] nodes,String[][] parentNodes,String targetNode2) { if(nodes == null || parentNodes == null){ throw new IllegalArgumentException(); } Map<String,String[]> map = new HashMap<String,String[]>(); for(int i = 0; i < nodes.length; i++){ map.put(nodes[i],parentNodes[i]); } //These are the parents visited as we go up Set<String> parentsSeen = new HashSet<String>(); parentsSeen.add(targetNode1); Queue<String> path = new LinkedList<String>(); String[] parents = map.get(targetNode1); //The root is the common parent if(parents == null){ return targetNode1; } //Build the path up for(String parent:parents){ path.add(parent); } while(!path.isEmpty()){ String currentParent = path.remove(); parentsSeen.add(currentParent); parents = map.get(currentParent); if(parents == null){ continue; } for(String parent:parents){ path.add(parent); } } parents = map.get(targetNode2); //It is the root,so it is the common parent if(parents == null){ return targetNode2; } //Start going up for the targetNode2. The first parent that we have already visited is the common parent for(String parent:parents){ if(parentsSeen.contains(parent)){ return parent; } path.add(parent); } while(!path.isEmpty()){ String currentParent = path.remove(); if(parentsSeen.contains(currentParent)){ return currentParent; } parents = map.get(currentParent); if(parents == null){ continue; } for(String parent:parents){ path.add(parent); } } return null; }
I didn't get a forward call Now that I'm "self-taught", I'm interested in understanding how I screwed up here As this is a technical problem, I don't think it is a subjective problem. I hope I can get help from experienced people So, as a colleague programmer, how would you handle this problem? How would you evaluate my solution? What do I need to do to improve my skills? You can be as straightforward as possible As long as I can understand what the problem is and learn it, I will be satisfied
Solution
I don't even know what "closest" means Consider the following chart:
I /\ / \ / \ H E |\ /| | \ / | G \/ D | /\ | | / F C |/ \| A B
There are two common ancestors a and B, h and E. h is the distance between a and B E is distance 1 from a, but distance b is 3 Which do I choose?
In addition, no matter what your answer to this question is, it doesn't work to find a group of ancestors from one person and then make a BFS from another person Find all ancestors of a, then BFS from B, find H first, find all ancestors of B, and then BFS from a, find e first. As an opponent, I can switch between a and B to make your algorithm fail, no matter what choice you make (2 / 2 or 1 / 3 is better)
Therefore, the correct algorithm must be more complex than ancestor set calculation plus BFS Unless you tell me how to make this choice, I'm not sure if I can determine the correct algorithm