Lowest Common Ancestor for a given pair of nodes - algorithm

I am stumbled by this question. The following is my approach:
Lets say the two nodes are node1 and node2
For any node (lets say node1), find the path from Root to
node1 and store it in an HashMap
For the other node node2, find the path from root to node2, and while traversing back,
check if any of the nodes are present in the hashmap or not
Return the first found node
Time Complexity is O(n) and Space Complexity is also O(h), where n is the height of the tree
I just wanted to know how good is this approach. Or whether there exists any other better solution.
EDIT: The given tree is Binary Tree and not BST. So, the time taken to find a node is linear to the size of nodes.

If you only need to do this once (or a few times), then this is a good method (you could optimize by going from the nodes towards the root, if possible). If you need to do this a lot of times for different pairs of nodes, it's worth to spend a bit more time precomputing certain things, which will speed up queries.
I think this article explains things very well. Post back if you have any questions please.

How's the tree represented? In particular, is there a reference to the parent node of any tree node? Is it an ordered tree?
Isn't it simpler to calculate the paths from node to root, then compare the paths from root to node? The last node that's the sanme on both paths is the common ancestor.
I think finding the path from root to node (as your approach has it) is O(n) where n is the size of the tree, unless the tree is ordered...
So your approach works, but if I were asking you the question I would have expected you to ask some additional questions about the layout of the tree in order to determine the correct answer...

Here is an instruction to solve Lowest Common Ancestor problem.
[Range Minimum Query and Lowest Common Ancestor][1]
[1]: http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor#Lowest Common Ancestor (LCA)

Related

Recommmend a proper data structure

I have an algorithm problem that needs binary tree structure similar to a binary tree. but the difference is that it may have nodes apart from the original tree independently.
And each node has three types. The first type is to point out starting node and only one exists. The second type is to point out connecting node and of course, and the last type is to point out a leaf node. Each edge has a cost to traverse to its bottom node.
Which data structure is good for me to cost to reach each node?
UPDATE
OK, I questioned this with data-structure tag so that I want to avoid to explain what the problem is. But inevitably, I explain about the problem because of lack of my explaination and my poor English.
I have nodes lists and edges with costs. There is a starting node(root node), nodes where will be located in the middle of a tree and leaf nodes are the destination for my program to traverse starting from a root node. But some of the leaf nodes may be ignored depending on the value in it. It is not important anyway. I have to calculate all leaf nodes' cost to reach its node from the root node and get the maximum value for them. Now, The problem is to adjust the cost value in edges for all other leaf nodes to have the same total cost with the maximum cost. But the sum of the adjust values has to be the minumum.

counting leaf nodes in a tree

Assume we have a tree where every node has pre-decided set of outgoing nodes. Is it possible to come up with a fast way/optimizations to count the number of leaf nodes given a level value? Would be great if someone could suggest any ideas/links/resources to do the same.
No. you'd still have to traverse the entire tree. There's no way of predicting the precise structure - or approximating it - from only the number of childnodes of each node of the tree.
Apart from that: just keep a counter and update it on each insertion. Far simpler and wouldn't change time-complexity of any operation, except for counting leaves, which would be reduced to O(1).
This can actually get pretty tough thing. As it varies of what is the programming language, what is the input data structure, is the tree binary or general tree (arbitrary number of children), size of the tree.
The most general idea is to run a DFS or BFS, starting from the root, to get every node level and then make a list of sets where each set contains the nodes of a single level. The set can be any structure, standard list is fine.
Let's say you are working in C++ which is good, if not the best practical choice if you need performance (even better than C).
Let's say we have a general tree and the input structure is adjacency list as you mentioned.
//nodes are numbered from zero to N-1
vector<vector<int>> adjList;
Then you run either a BFS or DFS, either will do for a tree, keeping a level for each node. The level for a next node is the level of it's parent plus one.
Once you discover the level, you put the node in like this.
vector<vector<int>> nodesPartitionedByLevels(nodeCount);
//run bfs here
//inside it you call
nodesPartitionedByLevels[level].push_back(node)
That's about it.
Then when you have the levels, you iterate all the nodes on that level and you check the adjaceny list if it contans any nodes.
basically you call adjList[node].empty(). If true than that is a leaf node.

How to find the number of edges or vertices between any two vertices of a tree?

Its a general tree (acyclic graph), so there can be only one such path. What algorithm can I use for this?
EDIT:
Need to find the paths for all pairs of vertices in the tree
I want to extend #templatetypedef's answer here1.
Note that in your problem, you need to do at least one write per each pair of nodes in the tree. There are n*(n-1)/2 of these.
Thus, in terms of big O notation, you cannot find an algorithm that runs better than O(n^2).
Now, use DFS or BFS to find the path per node. It will run in O(n+m) (n vertices, m edges). But since it is a tree, we know that m=n-1, giving us O(n) for BFS/DFS. Note that in a single BFS/DFS from some node v - you get d(v,u) for EVERY node u.
If you repeat it per each node, it will get you O(n^2) - which is optimal in terms of big O notation. I do agree you might get better constants with some optimizations, but that's about it.
(1) Started it as a comment, but it got too long and I figured it worth an answer.
One simple option is to do a depth-first search starting at one of the nodes until you reach the other node. You can then look at the path that was taken from the first node to the second, which must be the unique path between those nodes, and then count how many edges are in that path. This runs in linear time because a DFS on a tree only takes linear time.
Hope this helps!
You need to find the Lowest Common Ancestor (LCA). There are different approaches as you can study here: http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html
I have used the fallowing solution since I'm not fan to recursivity, that should work better for your problem since you need to find all the pairs in an efficient manner.
1-) Finding path between A -> B :
-Iterate starting from node A going up each parent node flagging each one with A Flag, until parent root fund.
-Iterate starting from node B going up until A Flag found. You have found LCA node.
- Result path is a list from A to LCA node, plus a reversed list from B to LCA node.
2-) Improvement finding A -> B :
- Iterate both nodes simultaneously, flagging with A Flag, and B Flag each ancestor node. Until A iterations find B Flag or B iterations find A Flag. Then the first to find another node flag has found the LCA node.
3-) Finding all pairs paths:
You can simply use solution above for each pair.
Or try to consider making a first pass iterating all the tree creating lists of flags, then a second pass to identify all LCA nodes for each pair, that would be inconvenient when the tree number of nodes grows too big.

What defines left and right in graphs and trees?

I'm learning about tree traversals and I can't seem to find any clear rules for how DFS or BFS algorithms decide which path to take first. I've seen variations of left first or least first.
Is left taken as being first child in the list?
Does this mean that (for a given node) the depth of a vertex in a graph that is part of a cycle is taken using the leftward path?
Also doesn't using a 'least first' rule make for a slower algorithm?
Thanks
Left is only meaningful for trees where the child nodes are oldered. Otherwise usually the author refers to first in the list of child nodes. Depth of a vertex is also not well defined in a graph that is not a tree, but if you refer to depth with respect to a given node that would usually be the shortest distance from the starting node.
I am not sure what does least first mean but if it refers to the key values of nodes and there is no ordering in the child nodes, finding the least will take more time of course.
Hope this helps.

Split 2-3 tree into less-than and greater-than given value X

I need to write function, which receives some key x and split 2-3 tree into 2 2-3 trees. In first tree there are all nodes which are bigger than x, and in second which are less. I need to make it with complexity O(logn). thanks in advance for any idea.
edited
I thought about finding key x in the tree. And after split its two sub-trees(bigger or lesser if they exist) into 2 trees, and after begin to go up and every time to check sub-trees which I've not checked yet and to join to one of the trees. My problem is that all leaves must be at the same level.
If you move from the root to your key and split each node so one points at the nodes larger than the key and the other at the rest and then make the larger node be a part of your larger tree, say by having the leftmost node at one level higher point at it, (don't fix the tree yet, do it at the end) until you reach the key you will get your trees. Then you just need to fix both trees on the path you used (note that the same path exists on both trees).
Assuming you have covered 2-3-4 trees in the lecture already, here is a hint: see whether you can apply the same insertion algorithm for 2-3 trees also. In particular, make insertions always start in the leaf, and then restructure the tree appropriately. When done, determine the complexity of the algorithm you got.

Resources