I'm currently working on LeetCode problem 108. Convert Sorted Array to Binary Search Tree:
Given an integer array nums where the elements are sorted in ascending order, convert it to a height-balanced binary search tree.
A height-balanced binary tree is a binary tree in which the depth of the two subtrees of every node never differs by more than one.
My code seems to be working fine but I don't know how to display the value null instead of None in my list. I need to print the BST in level order traversal. I'm looking for advice, hints or suggestions.
Input:
[-10,-3,0,5,9]
My current output:
[0, -3, 9, -10, None, 5, None]
Accepted output:
[0,-3,9,-10,null,5]
Here is my code:
from queue import Queue
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def sortedArrayToBST(nums: [int]) -> Optional[TreeNode]:
nbNodes = len(nums)
if nbNodes == 1:
root = TreeNode()
root.val = nums[0]
return root
elif nbNodes == 0:
root = TreeNode()
root.val = None
return root
middle = int(nbNodes / 2)
root = TreeNode()
root.val = nums[middle]
leftList = []
rightList = []
j = middle + 1
for i in range(middle):
leftList.append(nums[i])
if j != nbNodes:
rightList.append(nums[j])
j += 1
root.left = sortedArrayToBST(leftList)
root.right = sortedArrayToBST(rightList)
return root
def levelorder(root):
if root==None:
return
Q=Queue()
Q.put(root)
level_order_list = []
while(not Q.empty()):
node=Q.get()
if node==None:
continue
level_order_list.append(node.val)
Q.put(node.left)
Q.put(node.right)
print(level_order_list)
if __name__ == "__main__":
container = [-10,-3,0,5,9]
levelorder(sortedArrayToBST(container))
This is kind of a weird requirement that has nothing to do with the apparent main point of the problem and I suspect it's a result of the description being copied over from one that's aimed at another language (like Javascript, which uses null instead of None).
You can, however, format your list however you like when you print it; here's an example where we print a list by joining each item with "," (instead of the default ", ") and replace None with "null":
>>> my_list = [0, -3, 9, -10, None, 5, None]
>>> print("[" + ",".join("null" if i is None else str(i) for i in my_list) + "]")
[0,-3,9,-10,null,5,null]
Since JSON renders None as null, another option would be to dump the list to JSON and remove the " " characters:
>>> import json
>>> print(json.dumps(my_list).replace(' ', ''))
[0,-3,9,-10,null,5,null]
The problem is not related to null or None. LeetCode is a platform for taking code challenges in many different languages and they use JSON style to describe input/output, and in JSON notation None translates to null.
Not to worry about that. However, when you look at your output, there is a trailing None that should not be there. That means that you returned a BST that has a node with a None value. This should not happen.
The code that creates this None valued node is easy to identify... it is here:
elif nbNodes == 0:
root = TreeNode()
root.val = None
return root
return
When you think of it, this cannot be right: the number of nodes to generate (nbNodes) is 0, yet your code creates 1 node -- and that is one too many! In this case you should just return None to indicate that the parent node has no child here.
So replace with:
elif nbNodes == 0:
return
This fixes the issue you mentioned, and your code will now pass all tests on LeetCode.
Here is your code with the above corrections and with the self parameter restored (which you had removed to run it without the need to create a class instance):
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
nbNodes = len(nums)
if nbNodes == 1:
root = TreeNode()
root.val = nums[0]
return root
elif nbNodes == 0:
return
middle = int(nbNodes / 2)
root = TreeNode()
root.val = nums[middle]
leftList = []
rightList = []
j = middle + 1
for i in range(middle):
leftList.append(nums[i])
if j != nbNodes:
rightList.append(nums[j])
j += 1
root.left = self.sortedArrayToBST(leftList)
root.right = self.sortedArrayToBST(rightList)
return root
Other improvements
Unrelated to your question, but there are several things you can optimise:
Try to avoid creating new lists (leftList, rightList): copying values into them takes time and space. Instead use start/end indices in the original list to denote which sublist is currently processed.
Make use of the additional arguments you can pass to the TreeNode constructor. That way you don't have to assign to attributes after the constructor has run.
Use the integer division operator instead of the floating point division operator.
One of the two base cases is not needed as it would be dealt with correctly by the next recursive calls.
Here is a spoiler solution that applies those remarks:
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def recur(start: int, end: int):
if start < end:
middle = (start + end) // 2
return TreeNode(nums[middle],
recur(start, middle),
recur(middle + 1, end))
return recur(0, len(nums))
Related
Very new at Python and I'm trying to understand recursion over a binary tree. I've implemented a very simple tree, which funnily enough maps English characters to binary (1's and 0's). I've only used a very simple structure because I am struggling to get my head round a more complex question that I've been set. I figure if I can get my head round my example then I should be able to go away and look at the question I've been set myself.
The following creates the class BinaryTree and an instance of this
class BinaryTree:
"""A rooted binary tree"""
def __init__(self):
self.root = None
self.left = None
self.right = None
def is_empty(testtree: BinaryTree) -> bool:
"""Return True if tree is empty."""
return testtree.root == testtree.left == testtree.right == None
def join(item: object, left: BinaryTree, right: BinaryTree) -> BinaryTree:
"""Return a tree with the given root and subtrees."""
testtree = BinaryTree()
testtree.root = item
testtree.left = left
testtree.right = right
return testtree
EMPTY = BinaryTree()
C = join('C',EMPTY,EMPTY)
D = join('D',EMPTY,EMPTY)
E = join('E',EMPTY,EMPTY)
F = join('F',EMPTY,EMPTY)
A = join('A',C,D)
B = join('B',E,F)
BINARY = join('START',B,A)
I visualise it as follows
Visualisation of the Binary tree
Now I'm trying to create a function that will take two inputs, a BinaryTree and a single character and the output will be the binary code for the corresponding letter (as an example, D = " 10 "). I'm outputting as a string rather than an integer. My function and test case as follows
# global variable
result = ''
#Convert binary to letter
def convert_letter(testtree: BinaryTree, letter: str) -> str:
global result
if testtree == None:
return False
elif testtree.root == letter:
return True
else:
if convert_letter(testtree.left, letter) == True:
result += "1"
return result
elif convert_letter(testtree.right, letter) == True:
result += "0"
return result
#Test
test = 'D' #Return '10'
convert_letter(BINARY, test)
And unfortunately that's where I'm hitting a brick wall. I had tried initialising an empty string within the function, but everytime it iterates over the function it overwrites the string. Any help greatly appreciated.
The problem is that your function will sometimes return a boolean, sometimes a string, and sometimes None. So with this code:
if convert_letter(testtree.left, letter) == True:
result += "1"
return result
elif convert_letter(testtree.right, letter) == True:
result += "0"
return result
... you are not capturing all successful searches, as a successful search would return the actual string of "0" and "1" which obviously is not True. In that case the execution has no else to go to and returns None -- even when the letter was found in a deeper node.
Your function should not return a boolean -- that doesn't match the type hint either. It should be a string (the result). You could reserve None to indicate the letter was not found.
Some other problems:
result += "0" will append the digit, but since you already made the recursive call, you need to prepend the digit -- as you are higher up in the tree now.
The initialisation of your tree makes a different tree than you put in the image: A should be the left child, not the right child. So it should be join('START', A, B)
With those fixes, you'd have this code:
def convert_letter(testtree: BinaryTree, letter: str) -> str:
global result
if testtree is None:
result = None # Not found here
elif testtree.root == letter:
result = '' # Found! Start a path
elif convert_letter(testtree.left, letter) is not None:
result = "1" + result # Prepend
elif convert_letter(testtree.right, letter) is not None:
result = "0" + result # Prepend
else:
result = None # Not found here
return result
If you also correct to use join('START', A, B), then the output will be 10.
Better Practice
There are some things you can do better:
Don't use a global variable for storing the function result. As you return it, you can capture the result you get from a recursive call as a local variable, prepend to it, and return it again.
The definition of EMPTY makes your tree unnecessarily big. Just use None to denote an empty tree.
Don't call a node's value root. A rooted tree has only one root, and it is a node, not a value of a node. So call that attribute value or data, but not root.
The join function is nice, but why not use the constructor for that feature? The constructor can take those arguments as optional and immediately initialise the left and right attributes with those arguments.
The code-comment above the convert_letter function describes the opposite from what the function does.
Taking all that into account, your code could look like this:
class BinaryTree:
def __init__(self, value, left: 'BinaryTree'=None, right: 'BinaryTree'=None):
self.value = value
self.left = left
self.right = right
def convert_letter(tree: BinaryTree, letter: str) -> str:
if not tree:
return # Not found here, return None
if tree.value == letter:
return "" # Bingo: return an empty path
# No more global. path is a local variable
path = convert_letter(tree.left, letter)
if path is not None:
return "1" + path
path = convert_letter(tree.right, letter)
if path is not None:
return "0" + path
# Look how nice it is to create a tree using the constructor arguments
binary = BinaryTree("Start",
BinaryTree("A",
BinaryTree("C"), BinaryTree("D")
),
BinaryTree("B",
BinaryTree("E"), BinaryTree("F")
)
)
# Test
test = 'D'
print(convert_letter(binary, test)) # 10
I took the liberty of simplfying your code a bit let me know if you have any questions about how this works.
class node:
"""A rooted binary tree"""
def __init__(self, value = None, left = None, right = None):
self.value = value
self.left = left
self.right = right
C = node('C')
D = node('D')
E = node('E')
F = node('F')
A = node('A',C,D)
B = node('B',E,F)
BINARY = node('START',B,A)
def convert_letter(n,letter):
if n.value == letter:
return "1"+(convert_letter(n.left,letter) if not n.left is None else "")+(convert_letter(n.right,letter)if not n.right is None else "")
else:
return "0"+(convert_letter(n.left,letter) if not n.left is None else "")+(convert_letter(n.right,letter)if not n.right is None else "")
def walk(n):
return n.value+(walk(n.left) if not n.left is None else "")+(walk(n.right) if not n.right is None else "")
test = 'D'
print(convert_letter(BINARY, test))
print(walk(BINARY))
This is not how I would personally structure an answer, but I think it most closely follows what you are attempting. The shortcoming of your answer only being that you are only returning one value, but kind of tracking two values. Note, I have taken the liberty of correcting:
BINARY = join('START',A,B)
Let's modify your method to return both a Boolean indicating if the letter was found as well as the indicator of the path.
def convert_letter2(testtree: BinaryTree, letter: str):
if not testtree:
return (False, "")
if testtree.root == letter:
return (True, "")
test, val = convert_letter2(testtree.left, letter)
if test:
return (True, "1" + val)
test, val = convert_letter2(testtree.right, letter)
if test:
return (True, "0" + val)
return (False, "")
Then if we:
print(convert_letter2(BINARY, "D")[1])
We should get back "10"
++ EDIT ++
Thanks to all of you, I have taken many compartments to get the code to finally working.
Here's the full code overview
class Node:
# Binary Roots: Left and Right, initiating data
def __init__(self, data):
# Creating an object, Data, to be used for inputs
self.data = data
# The objects are defined as None, which creates an empty space for input
self.left = None
self.right = None
Define Binary Tree Class:
class BinaryTree:
# Defining Roots as Nodes, initiating at the same time.
def __init__(self, rootdata):
# Declaring roots as new nodes which uses root data
self.root = Node(rootdata)
Defining FindMax, which will find the maximum value in a binary tree, then return the maximum.
def FindMax(root):
# ???
if (root == None):
return float('-inf')
# In this function, it will search for the maximum of three values, the roots, and maximums from left and right leaves.
# Initialization of 3 things: the maximum of root, and two maximums of left and right leaves
letsfind = root.data
lfound = FindMax(root.left)
rfound = FindMax(root.right)
# If a maximum is found on the left, new maximum is the value.
if(lfound > letsfind):
letsfind = lfound
# If a maximum is found on the right, new maximum is the value.
if(rfound > letsfind):
letsfind = rfound
# Return the maximum value found.
return letsfind
???
if name == 'main':
# The Inputs of the Binary Tree and leaves.
# root (Top most), root.left (Left Leaf), root.right (Right Leaf)
root = Node(2)
root.left = Node(7)
root.right = Node(5)
root.left.right = Node(6)
root.left.right.left= Node(1)
root.left.right.right= Node(11)
root.right.right= Node(9)
root.right.right.left= Node(4)
# Print the Maximum
print("The Maximum Value in the Binary Tree is: ", FindMax(root))
I know it seems long, so I apologize.
I have taken account that the function 'FindMax' needs to be outside of the class, in order for it to run properly.
One more thing though, what is the purpose of the statement if __name__ == '__main__':?
And What is the if (root == None): return float('-inf') Really for?
Thanks a lot guys. I appreciate it! :)
lis = FindMax(start.left)
ris = FindMax(start.right)
You forgot to call the recursive search
Option 1
The problem is here
st = start.data
lis = start.left
ris = start.right
while you actually call for the data node on st. The other ones (lis and ris) are only been call as Nodes. You should change it with
st = start.data
lis = (start.left).data
ris = (start.right).data
to be reading the data from all nodes
Option 2
You override > for your node class.
Funny but a not for a rookie. If you are interested start reading this
This is the correct code:
def findMax(start):
# Base case
if start is None:
return float('-inf')
st = start.data
lis = findMax(start.left)
ris = findMax(start.right)
if (lis > st):
st = lis
if (ris > st):
st = ris
return st
and call findMax() now
Tree=BinaryTree("1")
Tree.root.left=Node("2")
Tree.root.right=Node("3")
Tree.root.left.left=Node("4")
Tree.root.left.right=Node("5")
Tree.root.right.left=Node("6")
Tree.root.right.right=Node("7")
Tree.root.right.right.right=Node("8")
print("Maximum element is", findMax(start))
def findMax(root):
if (root == None):
return float('-inf')
res = root.data
lres = findMax(root.left)
rres = findMax(root.right)
if (lres > res):
res = lres
if (rres > res):
res = rres
return res
if __name__ == '__main__':
root = newNode(2)
root.left = newNode(7)
root.right = newNode(5)
root.left.right = newNode(6)
root.left.right.left = newNode(1)
root.left.right.right = newNode(11)
root.right.right = newNode(9)
root.right.right.left = newNode(4)
print("Maximum element is", findMax(root))
#Output
Maximum element is 11
Note - There are a few exceptions to my answer:
It may contain errors as OP did not provide the BinaryTree class.
Does not take into account any logical issues.
It is focused on getting OP's code working.
Here are the errors that I spotted:
Python is a language which requires proper indentation. Indentation is vital in-order for code to function properly. It appears that the way you have indented your code is incorrect.
When you are trying to call a function inside a class, you would need to make the call either via an instance (self) or the class itself (classmethods). Explanation provided here.
Explanation of if __name__ == "__main__": here. It is not really required as I assume your code is a single module (in one Python file) but is good to have when working with multiple modules.
Based on the points I have mentioned, I have corrected your code accordingly as follows:
# Any required imports goes here...
# import XXX
class BinaryTree:
# OP did not provide code sample...
class Node:
def __init__(self, data):
# Creating a node
self.data = data
# Pointing either left or right, but it is empty in default
self.left = None
self.right = None
def fmax(self, start):
if start is None:
return 0
st = start.data
lis = self.fmax(start.left)
ris = self.fmax(start.right)
if (lis > st):
st = lis
if (ris > st):
st = ris
return st
if __name__ == "__main__":
Tree = BinaryTree("1")
Tree.root.left = Node("2")
Tree.root.right = Node("3")
Tree.root.left.left = Node("4")
Tree.root.left.right = Node("5")
Tree.root.right.left = Node("6")
Tree.root.right.right = Node("7")
Tree.root.right.right.right = Node("8")
print(Tree.fmax(Tree.root))
If anyone spots any error with my code please feel free to edit it. My idea is to get OP a working code and he can expand from there.
Given the following tree:
I should return the level order traversal of the tree from left to right:
so the above example would output a list of lists :
[ [3], [9,20], [15,7] ]
I wrote the following code, idea is storing the node value and its depth recursively in a Queue then iterate the Queue tuples and put the in intermediate list O if no more node of same depth append O to output and empty O and so on. However my code Timeout any help?
import queue
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
def helper(root,res,level):
if not root:
return res
l=level+1
res.put((root.val,level))
helper(root.left,res,l)
helper(root.right,res,l)
res=queue.Queue()
helper(root,res,0)
d=1
output=[]
node,depth=res.get()
output.append([node])
while res:
o=[]
node,depth=res.get()
while d ==depth:
o.append(node)
node,depth=res.get()
else:
d+=1
output.append(o)
return output
Here is my code for the Breadth First Search (BFS) Iterative Implementation with nodes in each level in the final output is under a single list:
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def BFS(self, root) -> int:
level=1
current=(root, level)
s=set()
result=[]
Q = [current]
while Q:
current=Q.pop()
level=current[1]
if current[0] not in s:
result.append([current[0].val, level])
s.add(current[0])
if current[0].left:
Q.insert(0,(current[0].left, level+1))
if current[0].right:
Q.insert(0,(current[0].right, level+1))
output=[]
temp=[]
level=1
for val in result:
if val[1]==level:
temp.append(val[0])
elif val[1] > level:
output.append(temp)
temp=[val[0]]
level+=1
output.append(temp)
return output
Testing:
n1=TreeNode(3)
n2=TreeNode(9)
n3=TreeNode(20)
n4=TreeNode(6)
n5=TreeNode(15)
n6=TreeNode(7)
n1.left=n2
n1.right=n3
n2.left=n4
n3.left=n5
n3.right=n6
sol1=Solution()
print(sol1.BFS(n1))
[[3], [9, 20], [6, 15, 7]]
Thanks for the answer from san. The solution helps me solve problem 107 of leetcode. I revised a little bit based on my understanding. There are two ways to solve this question but I prefer to use BFS fashion. This revised version compresses both value and level in the queue. It provides more flexibility comparing with only print the value of each node in the tree, as other tutorials provided.
# 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 levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
if root is None:
return None
level = 1
q = []
q.append((root,level)) # push both node and level.
save = []
while q:
cur = q.pop(0)
cur_node = cur[0]
cur_level = cur[1]
# print(cur_node.val)
# print(cur_level)
save.append([cur_node.val, cur_level])
if cur_node.left:
q.append((cur_node.left, cur_level+1))
if cur_node.right:
q.append((cur_node.right, cur_level+1))
print(save) # once print, you will have the idea about how to reorgnized the required output.
level = 1
output = []
temp = []
for i in range(len(save)):
cur = save[i]
#print(cur)
if cur[1] == level:
temp.append(cur[0])
if cur[1] != level:
output.insert(0, temp)
temp = []
temp.append(cur[0])
level = level + 1
if i == len(save)-1:
output.insert(0, temp)
return output
You can use the below logic , to print out nodes in BFS .
If you also need , you modify the method to return a list as well .
def levelOrder(root):
qroot = []
print(root.info,end=' ')
if root.left:
qroot.append(root.left)
if root.right:
qroot.append(root.right)
while(qroot):
tmp = qroot[0]
if tmp.left:
qroot.append(tmp.left)
if tmp.right:
qroot.append(tmp.right)
print (tmp.info,end=' ')
qroot.pop(0)
return
Instead of printing the values , you can directly keep appending the value to a new list and return the same .
I'm practicing creating a balanced binary search tree in python.
I already have these below, any idea on how to create a balance_bst funtion that passed a list of unique values that are
sorted in increasing order. It returns a reference to the root of a well-balanced binary search tree:
class LN:
def __init__(self,value,next=None):
self.value = value
self.next = next
def list_to_ll(l):
if l == []:
return None
front = rear = LN(l[0])
for v in l[1:]:
rear.next = LN(v)
rear = rear.next
return front
def str_ll(ll):
answer = ''
while ll != None:
answer += str(ll.value)+'->'
ll = ll.next
return answer + 'None'
# Tree Node class and helper functions (to set up problem)
class TN:
def __init__(self,value,left=None,right=None):
self.value = value
self.left = left
self.right = right
def height(atree):
if atree == None:
return -1
else:
return 1+ max(height(atree.left),height(atree.right))
def size(t):
if t == None:
return 0
else:
return 1 + size(t.left) + size(t.right)
def is_balanced(t):
if t == None:
return True
else:
return abs(size(t.left)-size(t.right)) <= 1 and is_balanced(t.left) and is_balanced(t.right)
def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
How do write the balance_bst?
def balance_bst(l):
Here is what I did:
def build_balanced_bst(l):
if l == None:
return None
else:
middle = len(l) // 2
return TN(l[middle],
build_balanced_bst(l[:middle]),
build_balanced_bst(l[middle + 1:]))
It gives me:
IndexError: list index out of range
How do I fix it?
I'm not going to write it for you since that's not what SO is about, but here's the general idea. Since the list is already sorted, the root should be the element in the middle of the list. Its left child will be the root of the balanced tree consisting of the elements to the left of the root in the list, and the right sub-tree will be the rest.
Hope someone can help, I'm not a programmer, but have been interested in exploring Fibonacci sequence and it's recursive tree...
I've created a Binary Tree class, along with an associated TreeNode class, and want to generate a binary tree of the recursive calls created by:
f(n) = f(n-1) + f(n-2) for a given value of n
I'd want to add it as an InsertFibonacci method of my Binary Tree class, replacing the standard Insert method:
def insertNode(self, root, inputData):
if root == None:
return self.addNode(inputData)
else:
if inputData <= root.nodeData:
root.left = self.insertNode(root.left, inputData)
else:
root.right = self.insertNode(root.right, inputData)
return root
Would I add somekind of decorator to the Fib function?
# Fib function
def f(n):
def helper(n):
left = f(n-1)
right = f(n-2)
return left,right
if n == 0:
return 0
elif n == 1:
return 1
else:
left, right = helper(n)
return left + right
Here's the simplest solution I can think of:
class FibTree(object):
def __init__(self, n):
self.n = n
if n < 2:
self.value = n
else:
self.left = FibTree(n - 1)
self.right = FibTree(n - 2)
self.value = self.left.value + self.right.value
Here's one way:
def insertFibonacci(self, n):
current = self.addNode(n)
if n > 1:
current.left = self.insertFibonacci(n-1)
current.right = self.insertFibonacci(n-2)
# if you want the fibonacci numbers instead of the calls:
# current.value = current.left.value + current.right.value
return current
Assumes positive n.
Should return the root of the fibonacci call tree.
Note that this won't exactly be the same kind of binary tree; it won't satisfy the ordering invariant that a binary search tree does. I'm assuming you just want to use your existing structure for convenience.