Is there a way to find a path in a tree? - algorithm

Let's say we have a tree like the one below. Is there an algorithm that given 2 nodes find the path that connects them. For example, given (A,E) it will return [A,B,E], or given (D,G) it will return [D,B,A,C,G]
A
/ \
B C
/ \ / \
D E F G

You will need to have a tree implementation where a child node has a link to its parent.
Then for both nodes you can build the path from the node to the root, just by following the parent link.
Then compare the two paths, starting from the ends of the paths (where the root is): as long as they are the same, remove that common node from both paths.
Finally you are left with two diverting paths. Reverse the second, and join the two paths, putting the last removed node in between the two.
Here is an implementation in JavaScript:
function getPathToRoot(a) {
if (a.parent == null) return [a];
return [a].concat(getPathToRoot(a.parent));
}
function findPath(a, b) {
let p = getPathToRoot(a);
let q = getPathToRoot(b);
let common = null;
while (p.length > 0 && q.length > 0 && p[p.length-1] == q[q.length-1]) {
common = p.pop();
q.pop();
}
return p.concat(common, q.reverse());
}
// Create the example tree
let nodes = {};
for (let label of "ABCDEFG") {
nodes[label] = { label: label, parent: null };
}
nodes.B.parent = nodes.C.parent = nodes.A;
nodes.D.parent = nodes.E.parent = nodes.B;
nodes.F.parent = nodes.G.parent = nodes.C;
// Perform the algorithm
let path = findPath(nodes.E, nodes.G);
// Output the result
console.log("Path from E to G is:");
for (let node of path) {
console.log(node.label);
}

Related

Using recursion to get the sum of a tree, but the root node won't add in Kotlin

I'm doing a question to get the sum of an entire tree through recursion, but the root node wont add with the child node. Now I'm aware that the root node is just a value while the child nodes are Tree nodes, so there not the same type.
class TreeNode<T>(var key: T){
var left: TreeNode<T>? = null
var right: TreeNode<T>? = null
}
fun treeSumR(root: TreeNode<Int>): Int{
if (root == null) return 0
return root.key + root.left?.let { treeSumR(it) } + root.right?.let { treeSumR(it) }
}
fun buildTree2(): TreeNode<Int>{
val one = TreeNode(1)
val two = TreeNode(2)
val four = TreeNode(4)
val eleven = TreeNode(11)
val three = TreeNode(3)
val four2 = TreeNode(4)
three.left = eleven
three.right = four
eleven.left = four2
eleven.right = two
four.right = one
return three
}
Any help is appreciated. Thanks.
There is an error on the + operators because you are adding a non-nullable Int (root.key) and nullable Int?s (the sums of the subtrees) together. The sums of the subtrees are nullable because you wrote ?.. Its effect is that the whole expression of root.left?.let { ... } evaluates to null if root.left is null.
You can provide a default value for the expression when it is null by using the elvis operator:
return root.key +
(root.left?.let { treeSumR(it) } ?: 0) +
(root.right?.let { treeSumR(it) } ?: 0)
However, since you are already checking if root is null and returning 0, a better way is to make root actually nullable, and pass root.left and root.right directly into it treeSumR:
// notice the question mark here
// v
fun treeSumR(root: TreeNode<Int>?): Int{
if (root == null) return 0
return root.key +
treeSumR(root.left) + // since treeSumR now takes a nullable node, you can directly pass the subtrees in
treeSumR(root.right)
}

how to solve the overlapping sub problems in Dynamic programming

Problem statement =>
You are given queries. Each query consists of a single number N. You can perform any of the 2 operations on in each move:
1: If we take 2 integers a and b where N=a*b (a>1,b>1), then we can change N=max(a,b).
2: Decrease the value of N by 1.
Determine the minimum number of moves required to reduce the value of N to 0.
here is the link for better understanding.
https://www.hackerrank.com/challenges/down-to-zero-ii/problem
I know here are some overlapping sub-problems and we can use DP to ignore the computation of same sub-problems again and again.
Now, my question is how in this problem, same sub-problems have same solutions. Because we have to solve this from top to bottom and sub-problem have same solution if we solved them from bottom to top.
For example
N=4
1 possibility = 4->3->2->1->0
2 possibility = 4->2->1->0
Now in above two possibility, 2 is repeating and I can use DP, but how I store their values. I mean, in 1 possibility solution of 2 is different from 2nd possibility because in first one I've to traverse 4->3->2 here solution of 2 is 2 and in 2nd possibility we traverse 4->2 and solution of 2 here is 1 now these 2 same sub-problems have different values because of the solving from top to bottom. Now I'm totally confused here. Please someone help me out in this.
The solution for a number N should store the minimun steps required to make it 0
this is how the sol should look
int dp[1000001];
memset(dp,-1,sizeof(dp);
int sol(N){
if(N == 2){
return 2;
}
if(dp[n]!=-1){
return dp[n]'
}
int sol = 1+sol(min(move1,move2));
dp[n] = sol ;
return sol;
}
EDIT 2:
I think this is a solution for your problem. The solution is in JavaScript:
// ****************************************************************************
function findPaths(tree, depth = 0, path = [], paths = [-1, []]) {
const [node, children] = tree
path.push(node)
if (!children) {
// console.log(path, depth)
if (paths[0] === -1 || paths[0] > depth) {
paths[0] = depth
paths[1] = [paths.length]
} else if (paths[0] === depth) {
paths[1].push(paths.length)
}
paths.push([...path])
path.pop()
return
}
children.forEach((el) => {
findPaths(el, depth + 1, path, paths)
})
path.pop()
return paths
}
// ****************************************************************************
function downToZero(n) {
const tree = [n]
const divisors = []
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
divisors.push(Math.max(i, n / i))
}
}
if (divisors.length) {
tree.push(divisors.map(downToZero))
} else if (n > 0) {
tree.push([downToZero(n - 1)])
}
return tree
}
// ****************************************************************************
function printPaths(paths) {
console.log('Total number of solutions:', paths.length - 2)
console.log('Total number of solutions with minimal moves:', paths[1].length)
console.log('Minimal moves:', paths[0])
paths[1].forEach((pathIndex) => {
let printPath = ''
paths[pathIndex].forEach((element) => {
printPath = `${printPath}${printPath === '' ? '' : '->'}${element}`
})
console.log(printPath)
})
console.log('')
}
// ****************************************************************************
// Test
printPaths(findPaths(downToZero(812849)))
printPaths(findPaths(downToZero(100)))
printPaths(findPaths(downToZero(19)))
printPaths(findPaths(downToZero(4)))

Tree from balanced parenthesis

I have to find height of tree and find protection number (or just to generate a tree) from balanced parentheses.
For example:
()()()() creates tree like a list with height 3.
I have no idea how to convert parentheses to tree. I found some 'answers':
http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf (second page contains all examples for tree with 4 nodes)
paragraph - Binary Trees, Forests, Non-Crossing Pairs :
https://sahandsaba.com/interview-question-generating-all-balanced-parentheses.html
However, I still don't know how to create a tree from such defined parentheses. I have some impression that in Knuth, authors treat it as something obvious.
Do I miss something or it's not that simple?
Is it necessary to create a forest and then a binary tree?
A pair of parentheses represents a node. What appears within those parentheses represents its left child's subtree (according to the same rules). What appears at the right of those parentheses represents the node's right child's subtree (again, according to the same rules).
The conversion of this encoding into a binary tree can be done recursively like this:
function makeBinaryTree(input):
i = 0 # character index in input
function recur():
if i >= input.length or input[i] == ")":
i = i + 1
return NIL
i = i + 1
node = new Node
node.left = recur()
if i >= input.length or input[i] == ")":
i = i + 1
return node
node.right = recur()
return node
return recur()
Here is an implementation in JavaScript that performs the conversion for each of those 4-noded trees, and pretty prints the resulting trees:
function makeBinaryTree(input) {
let i = 0; // character index in input
return recur();
function recur() {
if (i >= input.length || input[i++] === ")") return null;
let node = { left: recur(), right: null };
if (i >= input.length || input[i] === ")") {
i++;
return node;
}
node.right = recur();
return node;
}
}
// Helper function to pretty print a tree
const disc = "\u2B24";
function treeAsLines(node) {
let left = [""], right = [""];
if (node.left) left = treeAsLines(node.left);
if (node.right) right = treeAsLines(node.right);
while (left.length < right.length) left.push(" ".repeat(left[0].length));
while (left.length > right.length) right.push(" ".repeat(left[0].length));
let topLeft = "", topRight = "";
let i = left[0].indexOf(disc);
if (i > -1) topLeft = "┌".padEnd(left[0].length-i+1, "─");
i = right[0].indexOf(disc);
if (i > -1) topRight = "┐".padStart(i+2, "─");
return [topLeft.padStart(left[0].length+1) + disc + topRight.padEnd(right[0].length+1)]
.concat(left.map((line, i) => line + " " + right[i]));
}
// The trees as listed in Table 1 of http://www.cs.utsa.edu/~wagner/knuth/fasc4a.pdf
let inputs = [
"()()()()",
"()()(())",
"()(())()",
"()(()())",
"()((()))",
"(())()()",
"(())(())",
"(()())()",
"(()()())",
"(()(()))",
"((()))()",
"((())())",
"((()()))",
"(((())))"
];
for (let input of inputs) {
let tree = makeBinaryTree(input);
console.log(input);
console.log(treeAsLines(tree).join("\n"));
}
If I understood Knuth correctly, the representation works as the following: A pair of matching parentheses represents a node, e.g. () = A. Two consecutive pairs of matching parentheses means that the second node is the right child of the first one, e.g. ()() = A -> B. And two pairs of embedded parentheses means the inside node is the left child of the outside node, i.e. (()) = B <- A. Therefore, ()()()() = A -> B -> C -> D.
A possible algorithm to convert parentheses to binary tree would be:
convert(parentheses):
if parentheses is empty:
return Nil
root = Node()
left_start = 1
left_end = Nil
open = 0
for p = 0 to |parentheses|-1:
if parentheses[p] == '(':
open += 1
else
open -= 1
if open == 0:
left_end = p
break
root.left = convert(parentheses[left_start:left_end] or empty if index out of bound)
root.right = convert(parentheses[left_end+1:] or empty if index out of bound)
return root
It works by converting parentheses (L)R in the binary tree L <- A -> R recursively.

How to implement A* with minimum number of nodes on path?

I have implemented my A* algorithm such that it finds the shortest path to goal, given that it can move only to neighboring/adjacent cells. (Assume nodes are cells in a grid). So there's 8 surrounding cells it can move.
OOO
O*O
OOO
This works and finds the shortest path but what if I only want the nodes that are about 20-40 cells apart, and less if needed (say a door is only one cell away. How would I go about this without post processing the path?
So something like this?
XXXXOXOXOXXXX
XXXXXOOOXXXXX
OOOOOO*OOOOOO
XXXXXOOOXXXXX
XXXXOXOXOXXXX
Where O are the 'neighbors and X's are not.
def search(grid,start,goal):
dist = {}
visited = {}
predecessors= {}
hscore = {}
gscore = {}
gscore[start] = 0
hscore[start] = gscore[start] + heuristic(start,goal)
pq = PriorityQueue()
pq.put((hscore[start],start))
while not pq.empty():
current = pq.get()
if current[1] == goal:
return build_path(predecessors,goal)
visited[current[1]] = current[1]
max_dist = 0
succs = successors(grid,current[1],goal,pixels=90)
for successor in succs:
if visited.get(successor[0],None) != None:
continue
grid.grid[successor[0]] = (0,255,0)
g = gscore[current[1]] + 1
in_pq = successor[0] in pq
if (not in_pq or g < gscore[successor[0]] ):
predecessors[successor[0]] = current[1]
gscore[successor[0]] = g
hscore[successor[0]] = g + heuristic(successor[0],goal)
max_dist = dist
if not in_pq:
pq.put((hscore[successor[0]],successor[0]))
return []

Boost:Graph recursive traverse and graph-copy

I had some first experience with creating and traversing
graphs. But now I have a problem, of which I don't now,
if boost::graph has some algorithms to solve it.
Here is my graph-definition:
const int _AND = 1001;
const int _OR = 1002;
const int _ITEM = 1003;
struct gEdgeProperties
{
string label;
};
struct gVertexProperties
{
string label;
int typ; // _AND, _OR, ITEM
};
typedef adjacency_list< vecS, vecS, undirectedS, gVertexProperties, gEdgeProperties>
BGraph;
So BGraph contains items and logical relations between them.
Now I would like to transform this graph into multiple graphs,
each of which should contains NO or-relations, but represent
all by the OR-vertices defind combinatorial alternates
of items and their AND-relations.
An example: if there are three items A, B, C
related so: A AND ( B OR C)
then the result of the traversal should be two graphs,
containing the following combinations:
(1) A AND B
(2) A AND C
My (simple) idea now is to traverse the graph, and each time
the traversal finds an OR-vertex, to copy the whole
graph and follow from there on each part of the OR-node recursive:
if graph[vertex] == OR {
for (... // each child vertex of vertex
BGraph newGraph = copy(Graph);
traverse(newGraph,childVertex);
}
}
This won't work correctly, because my recursive call of each child
would miss the stack structure (the information, how to come back upwards
in the graph). This means: the traversal would climb down correct,
but not upwards again.
I have no idea, if there is a more (or at all) efficient way to solve such
a problem with boost::graph and its embedded algorithms.
But to me it seems to be an interesting problem, so I would like to
discuss it here, maybe it leads to a deeper insight of boost::graph.
Thank you!
My overall approach would be to do a depth-first walk of the input graph, and construct the output graphs bottom-up. Because you want to construct an arbitrary number of graphs, the traversal function has to return a list of graphs.
So here's an algorithm in pseudo-code
-- syntax: [xxx,xxx,...] is a list, and (xxx AND yyy) is a node.
traverse (node):
if typeof(node) == term
return [ node ]
else
leftlist = traverse(node.left)
rightlist = traverse(node.right)
if node.condition == OR
result = leftlist .appendAll( rightlist )
else if node.condition == AND
result = [ ]
foreach left in leftlist
foreach right in rightlist
result .append( (left AND right) )
else
panic("unknown condition")
return result
For example: pass in ((A OR B) AND (C OR D))
The individual terms compile to simple lists:
A -> [A]
B -> [B]
C -> [C]
D -> [D]
The OR conditions simply become parallel queries:
(A OR B) -> [A] OR [B] -> [A, B]
(C OR D) -> [C] OR [D] -> [C, D]
The AND condition must be combined in all possible permutations:
(... AND ...) -> [A, B] AND [C, D] ->
[(A AND C), (A AND D), (B AND C), (B AND D)]
Hope this helps. If you cast it into C++, you'll have to take care of housekeeping, i.e., destroying intermediate list objects after they are no longer needed.
Here the adoption to python as addition (Thanks again, it works great!!!):
_AND = 1
_OR = 2
_ITEM = 3
class Node:
def __init__(self, name):
self.name = name
self.condition = _ITEM
self.left = None
self.right = None
def showList(aList):
for node in aList:
print " elem cond: " , node.condition, " left: ", node.left.name, " right: ", node.right.name
def traverse (node):
leftlist = None
if node.condition == _ITEM:
return [ node ]
else:
leftlist = traverse(node.left)
rightlist = traverse(node.right)
found = 0
if node.condition == _OR:
found = 1
result = leftlist
for right in rightlist:
result.append(right)
else:
if node.condition == _AND:
found = 1
result = [ ]
for left in leftlist:
for right in rightlist:
newNode = Node(left.name + "_AND_" + right.name)
newNode.left = left
newNode.right = right
result.append(newNode)
if (found != 1):
print "unknown condition"
raise Exception("unknown condition")
return result
#EXAMPLE ((A OR B) AND (C OR D)):
node1 = Node("A")
node2 = Node("B")
node3 = Node("C")
node4 = Node("D")
node12 = Node("A_or_B")
node12.condition = _OR;
node12.left = node1
node12.right = node2
node34 = Node("C_or_D")
node34.condition = _OR;
node34.left = node3
node34.right = node4
root = Node("root")
root.condition = _AND;
root.left = node12
root.right = node34
aList = traverse(root)
showList(aList)

Resources