Finding the maximum height of left and right subtree - binary-tree

I would like to implement the following function:
def get_height(root, d):
if root.left:
left = get_height(root.left, d + 1)
if root.right:
right = get_height(root.right, d + 1)
The idea is simple: For a given node, I want the maximum height of its left and right subtree. The code is not finished yet obviously. I am looking for a clean way to finish the code above, so the return value is the max. height of the left and right subtree.

To just complete the method, you need to add a return and ensure that the base case works. The base case is when the node is a leaf. So you need to give default values for left and right:
def get_height(root, d):
left = d
right = d
if root.left:
left = get_height(root.left, d + 1)
if root.right:
right = get_height(root.right, d + 1)
return max(left, right)
This is however not the best practice. You should avoid the extra d parameter. You can do without, and let each call return the height of that node, without having to know anything about the parent. When the recursive call is made, the caller can add 1 to the returned value:
def get_height(root):
left = 0
right = 0
if root.left:
left = get_height(root.left) + 1
if root.right:
right = get_height(root.right) + 1
return max(left, right)
You can also move the base case one step further, so only one if is needed:
def get_height(root):
if not root:
return -1
return max(get_height(root.left), get_height(root.right)) + 1

Related

Fastest way to find path from top left to bottom right of a matrix

Say we have an n x m matrix with the cells either empty or full. The top left and bottom right cells are both empty. You can move up, down, left, or right. What is the fastest method to see if a path of length <= T of empty cells connects the top left and bottom right corner? I've tried both DFS and BFS with a matrix keeping track of how long it took to get to a particular cell, but both methods were too slow.
EDIT: I don't have access to the code anymore, but here's the pseudocode of what I did.
def find_path(grid, T):
visited = array(grid.dims)
visited.fill(0)
stack = []
stack.append((0, 0, T))
while len(queue) > 0:
pos = stack.pop()
if pos[0] == len(grid) and pos[1] == len(grid[0]):
return True
if pos[2] > 0:
if pos[0] < len(grid)-1 and grid[pos[0]+1][pos[1]] == empty and visited[pos[0]+1][pos[1]] < T-1:
visited[pos[0]+1][pos[1]] = T-1
stack.append(pos[0]+1, pos[1], T-1)
{same for right, left, up}
return False
I'm not quite sure what you're trying to do with the visited array, but "keeping track of how long it took to get to a particular cell" is not going to work with DFS, and is unnecessary with BFS. Probably the problems with your real code are in there somewhere.
The straightforward way to solve this is with a level-by-level BFS, like (in similar pseudocode):
def hasPath(grid,T):
gridcopy = copy(grid)
level=[(0,0)]
for pathlen in 1..T-1:
# Invariant: the positions in level are at path length pathlen
nextlevel=[]
for (x,y) in level:
# each valid direction is north plus maybe southwest and maybe southeast
for sw in 0..1, se in 0..1:
testx = x-sw+se
testy = y-1+sw+se
if testx >= 0 and
testy >= 0 and
testx < grid.width and
testy < grid.height and
gridcopy[testy][testx] == empty:
if testx==grid.width-1 and testy==grid.height-1
return True
nextlevel.append((testx,testy))
gridcopy[testy][testx] = blocked
level = nextlevel
return false

Difference between case 1 vs case 2?

I've worked on this question, Convert Sorted Array.
At first
I didn't know what to be returned in the end, so I created another function within the given one to carry out the recursion
**case 1**
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
def bst(num_list):
# base_case
if len(nums) < 2:
return TreeNode(nums[-1])
# recursive_case
mid = len(nums) // 2
node = TreeNode(nums[mid])
node.left = bst(nums[:mid])
node.right = bst(nums[mid + 1:])
ans = bst(nums)
return ans
but, it kept giving me 'time limit exceeded or maximum depth in recursion' as a result.
Then, as soon as I removed the inner 'bts' function and then just did the same recursion process the given function(sortedArrayToBST) itself, the error had gone just like magic...
**case 2**
def sortedArrayToBST(self, nums: List[int]) -> TreeNode:
if not nums:
return None
if len(nums) == 1:
return TreeNode(nums[-1])
# recursive_case
mid = len(nums) // 2
node = TreeNode(nums[mid])
node.left = self.sortedArrayToBST(nums[:mid])
node.right = self.sortedArrayToBST(nums[mid + 1:])
return node
However, having said that, I can't see what's different between the two codes. There must be a key difference between the two but can't work it out on my own.
Could you please enlighten me on what the difference is between case 1 and case 2 so what causes error in one but not in the other.
In case 1, the length of the processed list does not decrease across recursive calls because, while the parameter of bts is num_list, nums is being processed in its body. The error would disappear in case 1 if num_list is processed (instead of nums) in bts.

Recursive calls explanation in Binary Tree Maximum Path Sum

This is the problem:
Given a binary tree, find the maximum path sum.
For this problem, a path is defined as any sequence of nodes from some
starting node to any node in the tree along the parent-child
connections. The path must contain at least one node and does not need
to go through the root.
For example: Given the below binary tree,
1
/ \
2 3
Return 6.
The recursive solution for this problem looks like this:
int max = Integer.MIN_VALUE;
public int maxPathSum(TreeNode root) {
helper(root);
return max;
}
private int helper(TreeNode root) {
if (root == null) return 0;
int left = Math.max(helper(root.left), 0);
int right = Math.max(helper(root.right), 0);
max = Math.max(max, root.val + left + right);
return root.val + Math.max(left, right);
}
We call helper for left child and check if left child is greater than zero.
Then we call helper for right child and check if right child is greater then zero.
Then we check current max value with the sum root.val + left + right - this is also clear.
But then, in return statement we just have sum of root value and one of the children.
Why do we take only one child here but not two of them if they are both positive?
The recursive method does NOT return the solution itself, it only returns with the max value of that part. The final solution is computed in the max variable.
If you check the maxPathSum method it returns with the max value not the value returned from the helper method.
It is because it is possible that the solution doesn't touch the root, like here:
0
/ \
1 0
/ \ / \
2 3 0 0

stack frame on a binary tree traversal

I am having a hard time understanding the stack frame picture of a binary tree traversal
I have this function to calculate the height of a binary tree starting with the root node
public static int height(TreeNode<String> t){
if(t == null)
return -1;
int left = height(t.left);
System.out.println("left " +left);
int right = height(t.right);
System.out.println("right " +right);
if(left > right)
return left + 1;
else
return right + 1;
}
I have a binary tree setup as follows
Root
/ \
A B
The returned height value is 1 which is correct but I am having a hard time understanding the stack frame flow of the two recursive functions. What is the flow order like?
I get the following out values on my two print statements
left -1
right -1
left 0
left -1
right -1
right 0
Executions of height follow the tree shape in order.
height is called first on Root and then recursively on Root.left in line 4 and then again recursively on Root.left.left, which is null. At this point the last execution of height returns -1 and terminates. The remaining last execution assigns this to left and prints it.
This same execution nex calls height on Root.left.right. This is also null, so -1 is returned and printed, after which the if statement computes -1 + 1 == 0 and returns this.
We are now back to the call on Root.left, and the returned value 0 is assigned to left and is printed, whereupon the same execution calls height again and again on down to Root.right.left, which is null, so again -1 is printed.
You should see the pattern at this point.
left -1 A.left is null
right -1 A.right is null
left 0 Root.left is A
left -1 B.left is null
right -1 B.right is null
right 0 Root.right is B
But if you want a clearer picture you should probably code something like
public static int height(TreeNode<String> t){
if(t == null)
return -1;
int left = height(t.left);
System.out.println(t+" left "+left);
int right = height(t.right);
System.out.println(t+" right "+right);
if(left > right)
return left + 1;
else
return right + 1;
}
Not sure what exactly is your problem, but here it goes:
1) Initial call to height with root node
2) First recursive call to height with A node
3) Second recursive call to height with A.left (which is null)
4) First if statement fires, returns -1 - back to after the call in point 3)
5) First print statement - "left -1". Third recursive call to height with A.right (which is null)
6) if fires again, returns -1 - back to after the call in point 5)
7) Second print statement - "right -1".
8) left is -1 and right is -1, hence right + 1 is returned (0)- back to after the call in point 2)
9) Third print statement - "left 0".
10) Next recursive call of height with B node. Repeat steps 2-8 substituting B for A. Repeating this yields two print statements "left -1" and "right -1".
11) After getting back, right is 0 and thus the last print statement reads "right 0".
12) left is 0 and right is 0, hence right + 1 is returned

alternative rank function RBTree (red black tree)

I have an order-statistic augmented red black tree.
it works for the most part. but i need to implement a fast function (O(lg n)) that mostly returns the place of a node in sorted order. like the OS-rank function from my textbook. but with one twist: the return value if two nodes have the same score, should be the same. here is the os-rank function (in pseudocode, for a given node x, where root is the root of the tree).
OS-Rank(x)
r=x.left.size+1
y=x
while y!=root
if y==y.p.right
r+=y.p.left.size+1
y=y.p
return r
But: what i need is something where if A has key 1 and Node B has key 1, the function returns 1 for both. and so on. I tried myself with something like this.
rank(x)
start with value r=1
check that x.right is not Nil
case x.right has the same key as x
add x.right.#nodeswithkeyhigher(x.key) to r
other cases: add x.right.size to r
y=x
while y != root
if y.parent.left == y
case y.parent.right.key>x.key
add y.parent.right to r
other cases
add y.parent.right.#nodeswithkeyhigher(x.key) to r
y=y.parent
return r
Guess what: a testcase failed. I'd like to know if this is a correct way of doing things, or if perhaps i made some mistake i am not seeing (else the mistake is in the Node.#nodeswithkeyhigher(key) function).
edit: final paragraph for answer, thanks to Sticky.
tl;dr: skip to last paragraphs
This is the same issue I'm having trouble with. (Yes DS aswell). So far all runs except 5 are correct. I've tested several things, one being a very simple one: Just exchange left and right in OSRank. In some cases it gave a correct answer but in the harder cases it was quite a bit off. Oh I also added that if y.score == y.parent.score I only add the right size of y.parent, if not I add the right size + 1.
public int OSRank(Node x)
{
int r = x.Right.Size + 1;
Node y = x;
while (y != root)
{
if (y == y.Parent.Left)
{
if (y.Score == y.Parent.Score)
r = r + y.Parent.Right.Size;
else
r = r + y.Parent.Right.Size + 1;
}
y = y.Parent;
}
return r;
}
Let's first test this method on the tree on page 340 (figure 14.1). We'll search for the rank of 38 (which should return 4 because 39, 47 and 41 are higher):
r = 1 + 1 = 2 //Right side + 1
r = 2 //nothing happens because we're a right child
r = r + 1 + 1 = 4 //we're a left child, the key of our parent is larger and parent.Right.size = 1
r = 4 //nothing happens because we're a right child
So in this case the result is correct. But what if we add another node with key 38 to our tree. That reshapes our tree a bit, the right part of node 26 now looks like:
(I'm not allowed to add images yet so look here:http://i47.tinypic.com/358ynhh.png)
If we would use the same algorithm we'd get the following result (picking the red one):
r = 0 + 1 = 1 //no right side
r = 1 //we're a right child
r = 1 //we're a right child
r = 1 + 3 + 1 = 5 //The 3 comes from the size of node 41.
r = 5 //we're a right child
Though we expect rank 4 here. While I was typing this out I noticed that we check if y.Score == y.Parent.Score, but I completely forgot y changes. So in line 4 the clause "y.Score == y.Parent.Score" was false because we compared node 30 with 38. So if we change that line to:
if (x.Score == y.Parent.Score)
The algorithm outputs rank 4, which is correct. This means we eliminated another issue. But there are more, which I didn't figure out either:
The case in which Y.Parent.Right contains duplicate keys. Technically if we have 3 nodes with the same key, they should count as 1.
The case in which Y.Parent.Right contains keys that are equal to x.Key (the node you want the rank of). That would put us a few ranks back, incorrectly.
I suppose you could keep another integer which holds the amount of nodes with a higher score. Upon insertion you could climb the tree and adjust values if the subtree of that node doesn't contain a node with the same score. But how this is done (and efficiently) is unknown to me right now.
edit: First find the final successor of x with the same score x. Then calculate the rank the normal way. The code above works.

Resources