I am doing the above leetcode problem in Python. Typically what I do is I solve the problem in a jupyter notebook and then copy and paste it into the leetcode solution box once I am done with it. I am having issues with this problem, however.
The problem definition is defined below:
Given the root of a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST.
As a reminder, a binary search tree is a tree that satisfies these constraints:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
A sample input and output for the problem is shown below
Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
Output: [30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
Furthermore the problem solution is set up as follows
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def bstToGst(self, root: TreeNode) -> TreeNode:
I am confused as to how to approach this problem. Initially I thought I would do some sort of looping through the list provided. Upon reading some sample responses from the discussion, however, I see that commands such as root.right and root.left are used. How do I go about doing this in a jupyter notebook? I have no expereince with TreeNodes so I want to this the problem the right way and learn the fundamental concept instead of brute forcing through it another way. All help is greatly appreciated.
Thanks
Define an iterator function to traverse the nodes in reverse order, Then accumulate the total going backwards through the nodes and assign the values to each node:
class Solution:
def revNodes(self,node):
if node.right: yield from self.revNodes(node.right)
yield node
if node.left: yield from self.revNodes(node.left)
def bstToGst(self, root):
total = 0
for node in self.revNodes(root):
node.val = total = node.val + total
output:
data = [4,1,6,0,2,5,7,None,None,None,3,None,None,None,8]
nodes = [v if v is None else TreeNode(v) for v in data]
for i,node in enumerate(nodes):
if not node: continue
if 2*i+1<len(nodes): node.left = nodes[2*i+1]
if 2*i+2<len(nodes): node.right = nodes[2*i+2]
root = nodes[0]
print(root) # BEFORE
4
__/ \_
1 6
/ \ / \
0 2 5 7
\ \
3 8
Solution().bstToGst(root)
print([node.val if node else None for node in nodes])
[30, 36, 21, 36, 35, 26, 15, None, None, None, 33, None, None, None, 8]
print(root) # AFTER
30
__/ \__
36 21
/ \ / \
36 35 26 15
\ \
33 8
Note that, in order to print the tree, I had to add a repr() method to the TreeNode class
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __repr__(self):
nodeInfo = lambda n:(str(n.val),n.left,n.right)
return "\n".join(printBTree(self,nodeInfo,isTop=False))
The printBTree function is from another answer I provided in the past here
Related
The goal is, given the root of a binary tree, determine if it is a valid binary search tree (BST).
A valid BST is defined as follows:
The left subtree of a node contains only nodes with keys less than the node's key.
The right subtree of a node contains only nodes with keys greater than the node's key.
Both the left and right subtrees must also be binary search trees.
The problem setting is the same as here
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
level=[root]
while level:
for k in level:
if k.left:
if k.left >= k.val:
return False
if k.right:
if k.right <= k.val:
return False
level=[leaf for n in level for leaf in (n.left,n.right) if leaf]
return True
The above solution could not work for the case [2,1,3] which I believe the bug is located at this part after some debugging processes
if k.left:
if k.left >= k.val:
return False
What is wrong with it? Thanks in advance for any help.
There are a couple of issues with your code:
In the lines if k.left >= k.val: and if k.right <= k.val: you are comparing nodes to values, which I assume is not your intention.
Assuming the above is corrected, the general logic only compares the values of children with those of their immediate parents, which is not enough to satisfy the part of the problem specification stating, "The left subtree of a node contains only nodes with keys less than the node's key", or the symmetrical part of the spec regarding the right subtree. To satisfy this, you need to track the ancestral bounds with which a given node's val attribute must comply.
Here's an example of a modification to your code that would work as an iterative solution:
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
class Solution(object):
def isValidBST(self, root):
"""
:type root: TreeNode
:rtype: bool
"""
level=[(root,None,None)]
while level:
level2 = []
for k,floor,ceil in level:
if k.left:
if k.left.val >= k.val or floor is not None and k.left.val <= floor:
return False
level2.append((k.left,floor,k.val))
if k.right:
if k.right.val <= k.val or ceil is not None and k.right.val >= ceil:
return False
level2.append((k.right,k.val,ceil))
level = level2
return True
t = TreeNode(2, TreeNode(1), TreeNode(3))
x = Solution()
print(x.isValidBST(t))
Ouput:
True
Explanation:
instead of storing each non-null node at a given level, we store a tuple for each such node including the node itself as well as floor and ceil values (set to None for root) that will allow us to carry forward (or downward as we descend the levels of the tree) the bounds to which a given subtree must conform.
When we traverse leftward via a non-null left attribute, we overwrite ceil with the immediate parent's val attribute, and for rightward traversal via a non-null right attribute we overwrite floor.
I am kind of new in date structure.
In some Leetcode problems, the input given is say root = [1,2,3,4,5,null,6,7,null] and the type of root is TreeNode which seems to be a single node as follow
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
But the input here is clearly a "list": root = [1,2,3,4,5,null,6,7,null]
When I create a recursive function and it takes root as the input and maybe returns an integer, does it automatically start dealing with the first element in this tree even though the root here is a "tree" of elements? It seems to me many such functions call root and use it as a single variable (or node) instead of the entire tree which makes me confused sometimes. For example
def afunction(self, root: TreeNode) -> int:
queu = [root]
maxDepth = float('-inf')
result = 0
.....
The root here seems to be a node which doesn't really contain a value? And how to store it as queu = [root]?
The list likely represents a tree where the node at index i has its two children at indices 2*i + 1 and 2*i + 2. Your given list then represents the tree
1
(i=0)
/ \
2 3
(i=1) (i=2)
/ \ \
4 5 6
(i=3) (i=4) (i=6)
/
7
(i=7)
Under this interpretation, there's little distinction between the root and the tree rooted at the root node. Note, though, that a subtree is not a single slice of the tree, and concatenating two trees under a single root node does not correspond to simple list concatenation.
I'm currently trying to find the sum of all nodes in a specified subtree. For example if I have a tree
A(5)
/ \
B(5) C(6)
/ / \
D(3) E(3) F(7)
|
G(1)
and I want to know the the sum(C), which should return 17.
This is the code I came up with using recursion, but I can't seem to reach a subtree which has more than 2 levels. E.g. my algorithm doesn't seem to reach G. I'm trying to get better at recursion, but I can't seem to fix this.
def navigate_tree(node,key): #node of the root of subtree, along with its key
children = node.get_children()
if (len(children) ==0):
return node.key
else:
for child in children: #not a binary tree so trying to loop through siblings
key += navigate_tree(child,key) #summing up key recursively
return key
You would be better with an improved interface and being able to lean on the features of collections:
def navigate_tree(node):
children = node.get_children()
key = node.key
for child in children:
key += navigate_tree(child)
return key
# class Node and data A..G elided
print(navigate_tree(C))
Output:
17
The reason why your code appeared not to work, was that you were passing the previous key down to the next level of recursion. However, your code seemed to recurse OK. If you had added some print(node.key) you would have seen that you were visiting all the correct nodes.
You can use recursion with sum:
class Node:
def __init__(self, n, v, c=[]):
self.name, self.val, self.children = n, v, c
def get_sum(node):
return node.val+sum(map(get_sum, node.children))
tree = Node('A', 5, [Node('B', 5, [Node('D', 3)]), Node('C', 6, [Node('E', 3), Node('F', 7, [Node('G', 1)])])])
print(get_sum(tree.children[-1]))
Output:
17
However, if you do not have access to the exact node C, you can apply a simple search as part of the recursive function:
def get_sum(t, node):
def inner_sum(d, s=False):
return d.val*(s or d.name == t)+sum(inner_sum(i, s or d.name == t) for i in d.children)
return inner_sum(node)
print(get_sum('C', tree))
Output:
17
I am very confused about the question No.426 on leetcode, as I think my answer is right. But after running it shows I am wrong. Below is the question and my original answer:
"""
# Definition for a Node.
class Node:
def __init__(self, val, left, right):
self.val = val
self.left = left
self.right = right
"""
class Solution:
def treeToDoublyList(self, root):
"""
:type root: Node
:rtype: Node
"""
if root:
sign = True
stack = []
node = root
while stack or node:
if node:
stack.append(node)
node = node.left
else:
node = stack.pop()
if sign:
pre,head = node, node
else:
pre.right = node
node.left = pre
pre = node
node = node.right
head.left = pre
pre.right = pre
return head
else:
return None
Could someone help me to figure out what's wrong with my codes? Any comment or suggestion will be so appreciated.
I see two problems with the code.
First is that inside your if sign: block you need to set sign = False since you only want to initialize head once and execute that block only the first time. (Not sure why the variable is called sign, perhaps first would be more appropriate, or just reusing a head = None for that condition would have worked too.)
The second bug is smaller and affects the last link in the list to make it circular. You want to set pre.right = head instead of pre, so that the last node of the list points back at the first, not at itself.
I haven't really tested this, so it's possible I'm missing something, but it looks to me that this should be enough to fix this code.
According to the definition, a Binary Tree must satisfy the following conditions:
1. The left subtree of a node contains only nodes with keys less than
the the node's key.
2. The right subtree of a node contains only nodes with keys greater than the node's key.
3. Both the left and right subtrees must also be binary search trees.
My code is returning True for the input [10 ,5, 15, #, #, 6, 20] but it's incorrect, it must return False.
The input follows a level order traversal, where '#' signifies a path terminator where no node exists below.
Here is the tree:
10
/ \
5 15
/ \
6 20
Here is my code :
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
def isValidBST(self, root)
"""
:type root: TreeNode
:rtype: bool
"""
if not root:
return True
else:
if root.left and root.right:
return root.left.val < root.val < root.right.val and \
self.isValidBST(root.left) and self.isValidBST(root.right)
elif root.left and not root.right:
return root.left.val < root.val and self.isValidBST(root.left)
elif root.right and not root.left:
return root.right.val > root.val and self.isValidBST(root.right)
else:
return True
Consider a BST where A is the root value, B is the value at the root of its left subtree, and C is the value at the root of the right subtree under that. Your code will verify that A > B, and that B < C. But it does not check to see if A > C.
Or, from your example: It checks that 5<10, 10<15, 6<15, and 15<20, but does not check that 6>10.
Recall that the definition of a BST talks about all nodes in a subtree, not just the root.
Your algorithm doesn't implement frist two conditions properly. You should compare root value with maximum of left subtree and minimum of right subtree.
Alternatively, you can do an inorder traversal of the tree which should be in ascending order in binary search tree.