Problem Description
Given the root of a binary tree and two integers val and depth, add a row of nodes with value val at the given depth depth.
Note that the root node is at depth 1.
The adding rule is:
-
Given the integer
depth, for each not null tree nodecurat the depthdepth - 1, create two tree nodes with valuevalascur's left subtree root and right subtree root. -
cur's original left subtree should be the left subtree of the new left subtree root. -
cur's original right subtree should be the right subtree of the new right subtree root. -
If
depth == 1that means there is no depthdepth - 1at all, then create a tree node with valuevalas the new root of the whole original tree, and the original tree is the new root's left subtree.
Examples

Input: root = [4,2,6,3,1,5], val = 1, depth = 2
Output: [4,1,1,2,null,null,6,3,1,5]
Thought Process / Intuition
Once again, like yesterday, we have a tree problem. This time, we have to add a row of nodes at a certain depth. The problem is a bit more complex than yesterday's, but the approach is still the same.
I think both DFS and BFS would be able to work, but I decided to use DFS. The idea is to traverse the tree and when we reach the depth - 1, we add the new nodes.
Approach
- Create a dfs function that takes in the
rootand the currentdepth. - If the current
depthis equal to the targetdepth - 1, add the new nodes. - Then recursively call the dfs function on the left and right children of the current node.
- Finally, I return the
rootof the tree.
Initial Attempt
# 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 addOneRow(self, root: Optional[TreeNode], val: int, depth: int) -> Optional[TreeNode]:
if depth == 1:
new_node = TreeNode(val, root, None)
return new_node
def dfs(root, start_index):
if root is None:
return
temp1 = root.left
temp2 = root.right
if start_index == depth:
root.left = TreeNode(val)
root.right = TreeNode(val)
for child in [temp1, temp2]:
if child and child == temp1 and start_index == depth:
new_node = TreeNode(val, child, None)
root.left = new_node
if child and child == temp2 and start_index == depth:
new_node = TreeNode(val, None, child)
root.right = new_node
dfs(child, start_index + 1)
dfs(root, 2)
return root
Modified Solution
- After looking through Kurt's solution, I realised my code was very complex and could be solved more beautifully with recursion.
class Solution:
def addOneRow(self, root: Optional[TreeNode], val: int, depth: int):
if depth == 1:
new_node = TreeNode(val, root, None)
return new_node
def dfs(root, start_index):
if root is None:
return
if start_index == depth - 1:
root.left = TreeNode(val, left=root.left, right=None)
root.right = TreeNode(val, left=None, right=root.right)
dfs(root.left, start_index + 1)
dfs(root.right, start_index + 1)
dfs(root, 1)
return root
Complexity Analysis
Time complexity:
- The function operates in time, where n is the number of nodes in the binary tree.
- The function's time complexity is proportional to the number of nodes traversed. However, as we can terminate at a certain depth, the number of nodes traversed could actually be less than n.
- However, we care about the worst case. In the worst case, we would have to traverse all the nodes in the tree if the
depthis at the maximum depth of the tree. - Therefore, the time complexity is .
Space complexity:
- The space complexity is , where h represents the height of the binary tree. This accounts for the space used by the recursive call stack.
- In the worst-case scenario of a completely unbalanced tree, where the height equals the number of nodes , the space complexity becomes .
- Conversely, in the best-case scenario of a balanced tree, where the height is logarithmic , the space complexity is reduced to .