Minimum Depth of Binary Tree - returns None - binary-tree

I am working on LeetCode problem 111. Minimum Depth of Binary Tree:
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
Note: A leaf is a node with no children.
I have used a breadth first algorithm and tried to change it to align it to the problem. But the function is returning None.
Could anyone explain why that happens?
def minDepth(self, root: Optional[TreeNode]) -> int:
queue=[]
if root==None:
return 0
level=1
while(len(queue)>0):
n=len(queue)
for i in range(n):
node=queue.pop(0)
if not node.right and not node.left:
return(level)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
level+=1

The problem is that your queue is empty at the moment the loop is about to start.
You should place the root node in it:
if root is None:
return 0
queue = [root] # <----
level = 1
while queue:
# ...etc

Related

What is the pseudocode for this binary tree

basically i am required to come out with a pseudocode for this. What i currently have is
dictionary = {}
if node.left == none and node.right == none
visit(node)
dictionary[node] = 1
This is only the leaf nodes, how do i get the size for each node(parent and root)?
You can do a post-order traversal to find the size of each node.
The idea is to first handle both left and right trees. Then, after they are processed - you can use this data to process the current node.
This should look something like:
count = 0
if (node.left != none)
count += visit(node.left)
if (node.right != none)
count += visit(node.right)
// self is included.
count += 1
// update the node
node.size = count
return count
The dictionary for visited nodes is not needed since this is a tree, it guarantees to end.
As a side note - the size attribute of each node, is an important one. It basically upgrades your tree to a Order Statistics Tree
well the concept is that each node will know it's subtree size by first knowing the subtree size of all it's child which is maximum two child here as it is a binary tree, so once it knows subtree size of all child it can then add up all of them and atlast add 1 to it's
result and then the same thing will be done by it's parent also and so on upto root node. if we think about leaf node, it
has no child, so result subtree size will be only 1 in which it include itself.
one this idea is clear, it is easy to write code
that while traversing we will first know the subtree size of child nodes of current node then add 1 in it, in case of leaf node it will have subtree size of 1 only, below is the pseudocode of traverse funtion which finds the subtree size of each node and store them in dictionary sizeDictionary and a visited dictionary/array having larger scope has been used to keep track of visited nodes.
traverse(Tree curNode, dictionary subTreeSizeDictionary)
visited[curNode] = true
subtreeSizeDictionary[curNode] = 0
for child of curNode
if(notVisited[child])
traverse(child , sizeDictionary)
subtreeSizeDictionary[curNode] += subtreeSizeDictionary[child]
subtreeSizeDictionary[curNode] += 1;
here it is binary tree, but as you can see from pseudocode this concept can be used for any valid tree, the time complexity is O(n) as we visited each node only once.

Efficient way to search for a node with a specific attribute in a tree and assign the attributes of the tree

I have a tree. For example the following one:
root
a
/ \
b c
/ \ / \
e d f g
Every node in the tree has an attribute attr1. If a node's attr1 has a value of 1. Then the attr2 (another attribute) of all nodes on the path to this node, should make to 1. But we don't know if any of the nodes has a the value 1 in its attr1.
The idea I have to solve the problem is, to traverse through the tree (pre-order). While traversing I will have a FIFO container (queue) and every time I go downwards I will add to the queue and when going upwards I will remove the nodes which are bellow. So I have always the path to the current node. If then the node has attr1 == 1, then I must iterate the path again and set the attr2 of all nodes in the path to 2.
But I don't know if there is a more efficient way to accomplish this?
def update(node):
if node is None:
return False
upd_left = update(node.left)
upd_right = update(node.right)
node.attr2 = 1 if upd_left or upd_right or node.attr1 == 1 else node.attr2
return node.attr2 == 1
I think this will do what you expect as we are not iterating over the queue again and again.
The worst case complexity of your approach in case of a skewed tree will be O(n2). As for each node, you have to traverse the queue, if attr1==1 for each node.
But, in the above code, the complexity will be atmost O(n). Because you are visiting each node only once.

How find the longest consecutive path in a binary tree

I was asked in an interview this question. Consider a binary tree, we need to print the length of the longest path, where each element differs by 1.
EG:
6
/ \
5 7
/ \ / \
2 4 8 9
answer: 5
( 4,5,6,7,8 )
How to do this?
I developed an algoirthm to print increasing path from root to leaf, but I was not to develop one that keeps track of path that's on both subtrees.
EDIT: Need to get back the original tree after modification.
As suggested by #qwertyman in the comments
remove all invalid edges i.e edges whose difference is greater than 1
Now we have a forest, for each forest calculate the diameter as it is given in #Filip Kočica solution
The answer would be the max diameter out of all forests
For each subtree, you can calculate the longest increasing path down from the subtree root, the longest decreasing path down, and the longest internal path consisting of the increasing and decreasing paths down from the same node anywhere in the subtree.
It's easy to calculate these for a node if you already have them for all of its children, so you can do it as part of any postorder traversal.
The answer is the longest internal path within the whole tree.
Let longest_desc[a] be the longest 1-by-1 descending path going down from a
Similarly longest_asc[a], the longest 1-by-1 incremental path going down from a
For a fixed root R, the answer would be longest_desc[R] + longest_asc[R] - 1.
A brut force solution would do 2 dfs/bfs traversals from each node X to compute longest_asc[X] and longest_desc[X] and then merge them together. The resulting runtime complexity would be O(n^2).
But we can actually do better using dynamic programming:
longest_asc[X] = max(longest_asc[Y in children[X]] with Y = X + 1)
longest_desc[X] = max(longest_desc[Y in children[X]] with Y = X - 1)
Then we can compute all the values in a single DFS traversal => O(n) solution.
The answer is incorrect - another user correctly pointed out a bug. My solution below works only when the max length path passes through the root. In case, for example, the max length path is entirely in the left subtree and does not pass through the root, this answer fails. Feel free to read further to acquaint yourself with a recursive solution... and the bug in it.
I'm assuming that it is not important that the path has to have a difference of +1 as shown in your example. A difference of -1, resulting in a path like 4 -> 5 -> 4 -> 3 -> 4 -> 5 is ok as well.
public int getLongestConsecutivePath(TreeNode root) {
return root == null
? 0
: getLength(root.left, root.value) + getLength(root.right, root.value);
}
private int getLength(TreeNode node, int prevVal) {
return node == null || Math.abs(node.value - prevVal) > 1
? 0
: Math.max(getLength(node.left, node.value), getLength(node.right, node.value)) + 1;
}
Explanation:
If the root is not null, we get the max length in left and right subtree and sum it.
To get max length in a subtree, we recursively get the max length of right and left subtree of the subtree.
If we have reached the leaf OR if we have reached a node where the difference in value is greater than 1, we return 0.
Else we recursively get the max length from the left and right subtree and add 1 to it to accommodate for this node itself.

How to find all shortest paths

I have a graph and I want to find all shortest paths between two nodes. I've found a shortest path between two nodes by BFS. However, it just gives me one of the shortest paths if there exists one more than.
How could I get all of them using BFS?
I've implement my code from well-known BFS pseudocode.
Also, I have a adjacency list vector which holds adjacency vertices for all nodes.
You can easily do it by maintaining a list or vector of parents for each node.
If two or more nodes ( say X, Y, Z) at the same distance from the starting node , leads to another node M , make all X , Y and Z as the parents of M.
You just have to add a check to see while adding a parent to the node whether that parent is in the same level as the previous parents.
By level , I mean the distance from the starting point.
This way you can get all the shortest paths by tracing back the parent vectors.
Below is my C++ implementation.
I hope you know how to print the paths by starting from the destination ,tracing the parents and reach the starting point.
EDIT : Pseudo Code
bfs (start , end)
enqueue(start)
visited[start] = 1
while queue is NOT empty
currentNode = queue.front()
dequeue()
if(currentNode == end)
break
for each node adjacent to currentNode
if node is unvisited
visited[node] = visited[curr] + 1
enqueue(node)
parent[node].add(currentNode)
else if(currentNode is in same level as node's parents)
parent[node].add(currentNode)
return
If the graph is large, finding all paths from start to end and then selecting the shortest ones can be very inefficient. Here is a better algorithm:
Using BFS, label each node with its distance from the start node. Stop when you get to the end node.
def bfs_label(start, end):
depth = {start: 0}
nodes = [start]
while nodes:
next_nodes = []
for node in nodes:
if node == end:
return depth
for neighbor in neighbors(node):
if neighbor not in depth:
depth[neighbor] = depth[node] + 1
fringe.append(neighbor)
Using DFS, find all paths from the start node to the end node such that the depth strictly increases for each step of the path.
def shortest_paths(node, end, depth, path=None):
if path is None:
path = []
path.append(node)
if node == end:
yield tuple(path)
else:
for neighbor in neighbors(node):
if neighbor in depth and depth[neighbor] == depth[node]+1:
for sp in shortest_paths(neighbor, end, depth, path):
yield sp
path.pop()
A simpler way is to find all paths from source to destination using dfs. Now find the shortest paths among these paths. Here is a sudo code:
dfs(p,len)
if(visited[p])
return
if(p== destination)
paths.append(len)
return
visited[p]=1
for each w adjacent to p
dfs(w,len+1)
visited[p]=0
You can find the path by maintaining an array for paths. I will leave that to you as an assignment
We can use a simple BFS algorithm for finding all the shortest paths. We can maintain the path along with the current node. I have provided the link to the python code for the same below.
https://gist.github.com/mridul111998/c24fbdb46492b57f7f17decd8802eac2

How would a DFS be meaningful for a digraph, rather than a BST?

I'm working on better understanding the application of a depth-first search algorithm. I understand how to use it to traverse a binary search tree to produce a sorted list. My Python implementation looks like this:
class bst_node:
def __init__(self, x):
self.x = x
self.left = None
self.right = None
def get_dfs_path(bst_node):
""" Returns a depth-first search path for a BST """
left = [] if bst_node.left == None else get_dfs_path(bst_node.left)
right = [] if bst_node.right == None else get_dfs_path(bst_node.right)
return left + [bst_node] + right
Which works quite nicely. I'm struggling to understand, however, whether this algorithm can be meaningfully applied to a digraph in general, rather than the more strict BST. Consider the following digraph node implementation:
class di_node:
def __init__(self, x):
self.x = x
self.visited = False
self.children = []
Since a node in a digraph can have an arbitrary number of children, the dfs logic can't simply construct the path as dfs_path(left) + parent_node + dfs_path(right). Can someone help me understand if/how dfs applies to a digraph?
EDIT
Ok, based on the responses let me attempt a dfs traversal for a di_node. Please let me know if I'm anywhere close to the mark:
def get_dfs_path(di_node):
""" Returns a depth-first search path for a digraph """
if di_node.visited:
return []
else:
di_node.visited = True
return [di_node] + [ get_dfs_path(child) for child in di_node.children) ]
As you noticed in-order traversal (left-subtree, current node, right subtree) doesn't make much sense for general graphs since a node can have more than two subtrees. However a depth first search can also use pre-order (process the current node first, then the subtrees) or post-order (first process the subtrees, then the current node) traversal. Those two work just fine with graphs.
One thing you have to keep track of when performing DFS on graphs is which nodes you already visited. Otherwise you'd get infinite loops when traversing cyclic graphs.
You can use DFS in a graph to detect cycles. Keep track of visited nodes and if you visit a node that was already visited then you have detected a cycle.

Resources