I'm trying to solve LeetCode 199.
Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
I've already solved this problem by using Level-Order-Traversal with time complexity of O(n) & memory complexity of O(n).
I'm wondering if it's possible to optimize the solution, and solve this problem iteratively with constant memory complexity of O(1) without using any data structure.
My solution with time & memory of O(n):
# 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:
# time complexity: O(n), memory complexity: O(n)
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root: return []
res = []
q = collections.deque([root])
while q:
len_q, level = len(q), []
for _ in range(len_q):
node = q.popleft()
level.append(node)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
res.append(level[-1].val) # add the last element of each level (right most element)
return res
The memory allocated for the output can be used as a stack to trace the state of the depth-first traversal. Although that is O(n), this is memory that was needed anyway for the output. Besides that there is only O(1) of auxiliary memory used.
Some specifics about that stack:
Here is how you could implement that:
"""
A stack implementation that never really deletes values as we pop,
but only adjusts a size attribute.
This way the backing list will retain for each depth the last value
that was on the stack at that depth.
"""
class Stack(list):
def __init__(self):
super().__init__()
self.size = 0
def push(self, value):
if len(self) == self.size:
self.append(value)
else:
self[self.size] = value
self.size += 1
def pop(self):
if self.size:
self.size -= 1
return self[self.size]
class Solution:
def rightSideView(self, node: Optional[TreeNode]) -> List[int]:
stack = Stack()
while True:
# Follow path down the tree to the left-most leaf
while node:
stack.push(node if node.left and node.right else node.val)
node = node.left or node.right
# Backtrack up the tree to a node whose second child has not been explored
node = stack.pop()
while node is not None and not isinstance(node, TreeNode):
node = stack.pop()
if node is None: # all done
return stack # this is a list of values overloaded with a size attribute
# Go down into the right subtree
stack.push(node.val)
node = node.right