Reputation: 1705
For Leetcode 105 I've got the O(N^2)
solution working and I'm attempting to optimize to an O(N)
solution but the output tree is the wrong structure.
Given two integer arrays preorder and inorder where preorder is the preorder traversal of a binary tree and inorder is the inorder traversal of the same tree, construct and return the binary tree.
My original O(N^2)
solution.
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
preorder_queue = deque(preorder)
def helper(preorder, inorder):
if not preorder or not inorder:
return None
root = TreeNode(preorder.popleft())
root_index = inorder.index(root.val)
root.left = helper(preorder, inorder[:root_index])
root.right = helper(preorder, inorder[root_index+1:])
return root
return helper(preorder_queue, inorder)
The slow operation is here is the inorder.index(root.val)
since an index
operation in a list is O(N)
. I'm trying to optimize this by storing a map of Node values -> indexes
in my solution below.
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
preorder_queue = deque(preorder)
cache = {}
for i, node_val in enumerate(inorder):
cache[node_val] = i
def helper(preorder, inorder):
if not preorder or not inorder:
return None
root = TreeNode(preorder.popleft())
root_index = cache[root.val]
root.left = helper(preorder, inorder[:root_index])
root.right = helper(preorder, inorder[root_index+1:])
return root
return helper(preorder_queue, inorder)
However for the input preorder = [3,9,20,15,7]
and inorder = [9,3,15,20,7]
my output is giving me [3,9,20,null,null,15,null,7]
instead of the correct tree structure [3,9,20,null,null,15,7]
. Can anyone explain what's wrong with the cache solution?
Upvotes: 1
Views: 118
Reputation: 350137
The reason for the different output is this:
In the first version the value of root_index
is taken from the local name inorder
, which in general is just a slice of the original inorder
(see how the recursive call is made with such a slice as argument). So the value of root_index
is an index that is meaningful to the slice, but not to the overall, initial inorder
list. Yet the second version of the code will give root_index
an index that is meaningful in the initial inorder
list, not to the local slice of it.
You can fix that by not creating a local inorder
name (as parameter), but instead pass start
and end
indices which define which slice should be assumed, without actually creating it. That way the code can continue with the initial inorder
list and use the indexing that the cache
offers.
So:
def helper(preorder, start, end):
if not preorder or start >= end:
return None
root = TreeNode(preorder.popleft())
root_index = cache[root.val]
root.left = helper(preorder, start, root_index)
root.right = helper(preorder, root_index+1, end)
return root
return helper(preorder_queue, 0, len(inorder))
Upvotes: 1