Given the root
of a binary tree, return all root-to-leaf paths in any order.
A leaf is a node with no children.
Example 1:
Consider the following binary tree:
1
/ \
2 3
\
5
Input: root = [1,2,3,null,5]
Output: ["1->2->5","1->3"]
Example 2:
Consider the following binary tree:
1
Input: root = [1]
Output: ["1"]
Write a function that takes the root of a binary tree as input and returns a list of strings, where each string represents a root-to-leaf path. The paths can be in any order.
Constraints:
[1, 100]
.-100 <= Node.val <= 100
A straightforward approach is to perform a Depth-First Search (DFS) traversal of the binary tree. During the traversal, we maintain a string representing the current path from the root to the current node. When we reach a leaf node (a node with no children), we add the current path to our list of paths. The downside of this approach is the string concatenation.
paths
to store the root-to-leaf paths.dfs(node, current_path)
:
None
, return.current_path
string.current_path
to the paths
list.dfs
for the left child, updating current_path
.dfs
for the right child, updating current_path
.dfs
function starting from the root node with an empty string as the initial path.paths
list.class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def binaryTreePaths(root):
paths = []
def dfs(node, current_path):
if not node:
return
current_path += str(node.val)
if not node.left and not node.right:
paths.append(current_path)
return
if node.left:
dfs(node.left, current_path + "->")
if node.right:
dfs(node.right, current_path + "->")
dfs(root, "")
return paths
Where N is the number of nodes in the tree. In the worst case, for a skewed tree, the string concatenation in each recursive call can take O(N) time, and we visit each node once.
In the worst case, for a skewed tree, the recursion depth can be O(N). Additionally, storing the paths list can take O(N) space in the worst case.
Instead of using string concatenation, we can use a list to store the current path. This avoids the O(N) time complexity of string concatenation in each recursive call. When we reach a leaf node, we convert the list to a string only once. Also, we need to backtrack by removing the last element in list for the next branch.
Initialize an empty list paths
to store the root-to-leaf paths.
Define a recursive function dfs(node, current_path)
:
None
, return.current_path
list.current_path
list to a string with "->" as the separator.paths
list.dfs
for the left child, updating current_path
.dfs
for the right child, updating current_path
.Call the dfs
function starting from the root node with an empty list as the initial path.
Return the paths
list.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def binaryTreePaths(root):
paths = []
def dfs(node, current_path):
if not node:
return
current_path.append(str(node.val))
if not node.left and not node.right:
paths.append("->".join(current_path))
current_path.pop()
return
if node.left:
dfs(node.left, current_path)
if node.right:
dfs(node.right, current_path)
current_path.pop()
dfs(root, [])
return paths
Where N is the number of nodes in the tree. We visit each node once, and the list operations (append and pop) take O(1) time. Converting the list to a string takes O(K) where K is the length of the path, but in total this does not exceed O(N).
In the worst case, for a skewed tree, the recursion depth can be O(N). Additionally, storing the paths list can take O(N) space in the worst case. The current_path
list also takes O(N) space in the worst case.