Skip to content
Open

trees 1 #1741

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions pre-in.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# O(n^2) time bc .index takes O(n) and you do it N times
# O(n^2) space $O(N^2)$While the recursion depth is $O(N)$, each call creates new list slices. Summing the memory of these slices across all levels of the recursion tree results in $O(N^2)$ total space used during the process.
# 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 __init__(self, val=0,left=None,right=None):
self.val = val
self.left = left
self.right = right

def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
# both inorder and postorder are required to reconstruct the tree
# with just one and not the other you don't know which is root

# in order: left, root, right
# pre order: root, left, right

if not preorder:
return None

rootVal = preorder[0] # 3
rootIdx = inorder.index(rootVal) # get the index of 3 in inorder

inLeft = inorder[:rootIdx] # inorder left subtree [8,9]
inRight = inorder[rootIdx+1:] # inorder right subtree [15,20,7]
preLeft = preorder[1:1+len(inLeft)] # [9,8]
preRight = preorder[1+len(inLeft):] # [20,15,7]

root = TreeNode(rootVal)
root.left = self.buildTree(preLeft, inLeft)
root.right= self.buildTree(preRight, inRight)

return root

# How to optimize this to O(N)
# To reach linear time and space, you need to stop copying the lists and stop searching for the index manually.
# Use a Hash Map: Store the inorder values and their indices in a dictionary: {val: index}.
# This makes finding rootIdx an O(1) operation.Use Pointers: Instead of slicing lists (which creates copies),
# pass the start and end indices of the current subtree range.

# use a hashmap with pointers
class Solution:
def buildTree(self, preorder, inorder):
self.idx = 0
# Create an empty dictionary
inorder_map = {}

# Use a standard loop with enumerate to fill it: { val: i }
for i, val in enumerate(inorder):
inorder_map[val] = i
return self.helper(preorder, 0, len(inorder) - 1, inorder_map)

def helper(self, preorder, start, end, inorder_map):
if start > end:
return None
# move preorder index by 1 each time
rootVal = preorder[self.idx]
self.idx+=1
root = TreeNode(rootVal)
rootIdx = inorder_map[rootVal]
root.left = self.helper(preorder,start,rootIdx-1,inorder_map)
root.right = self.helper(preorder, rootIdx+1,end,inorder_map)

return root





58 changes: 58 additions & 0 deletions validate-bst.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# 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 __init__(self):
# pay attention to global vs parameter of recursion
# prev cannot go into the recursion stack
self.flag = True
self.prev = None
def isValidBST(self, root: Optional[TreeNode]) -> bool:
self.helper(root)
return self.flag

# you cannot pass prev into the helper. Track what goes into the recursive stack only
# when recursion stack unfolds, the parameters of recursion will be overwritten
def helper(self,root):
if root == None:
return
# if I got a breach, exit - can save some of the nodes
if not self.flag:
return
print(root.val)
self.helper(root.left)
if self.prev != None and root.val <= self.prev.val:
self.flag = False
# even if you add a return here, all recursive calls are still completed because
# return returns to the same place from where we called it
# whatever goes into the recursion stack will come out

self.prev = root
self.helper(root.right)


# can also use range:

class Solution:
def __init__(self):
# pay attention to global vs local scope.
# prev cannot go into the recursion stack
self.flag = True
self.prev = None
def isValidBST(self, root: Optional[TreeNode]) -> bool:
self.helper(root,None,None)
return self.flag

def helper(self,root,min,max):
if root is None:
return

self.helper(root.left,min,root.val)
if max != None and root.val >=max:
self.flag=False
if min != None and root.val <= min:
self.flag=False
self.helper(root.right,root.val,max)