Recursive
Like binary search, we recursively make mid the root and mid‘s left and right sub-lists the left and right subtrees.
Time: There are levels and due to slicing, each level has
copies. So, like merge-sort, total time is
.
Space: .
# 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 sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None
if len(nums) == 1:
return TreeNode(nums[0])
mid = len(nums) // 2
root = TreeNode(nums[mid])
left_subtree = self.sortedArrayToBST(nums[ : mid])
right_subtree = self.sortedArrayToBST(nums[mid+1 : len(nums)])
root.left = left_subtree
root.right = right_subtree
return root
Slicing is not necessary, we could pass around (lo, hi) — significantly reducing complexity.
Time: .
Space: .
# 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 make_bst(self, nums, lo, hi) -> Optional[TreeNode]:
if lo > hi:
return None
if lo == hi:
return TreeNode(nums[lo])
mid = (lo+hi) // 2
root = TreeNode(nums[mid])
left_subtree = self.make_bst(nums, lo, mid-1)
right_subtree = self.make_bst(nums, mid+1, hi)
root.left = left_subtree
root.right = right_subtree
return root
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
return self.make_bst(nums, 0, len(nums)-1)
Iterative
With an explicit stack we simulate the bottom-up recursion using visited set and nodes dict. Second time we visit a range, on the return path, the TreeNode‘s of the child ranges have already been created.
# 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 sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None
visited = set()
nodes = {}
root = (0, len(nums)-1)
stack = [root]
while stack:
u = stack.pop()
if u not in visited:
visited.add(u)
lo, hi = u
mid = (lo+hi) // 2
stack.extend( c for c in (u, (lo, mid-1), (mid+1, hi)) if c[0] <= c[1] )
continue
# Return path: u's children are available
lo, hi = u
mid = (lo+hi) // 2
u_node = TreeNode(nums[mid])
left_subtree = nodes.get((lo, mid-1), None)
right_subtree = nodes.get((mid+1, hi), None)
u_node.left = left_subtree
u_node.right = right_subtree
nodes[u] = u_node
return nodes[root]
Leave a comment