Problem

Given a binary tree where each path going from the root to any leaf form a valid sequence , check if a given string is a valid sequence in such binary tree.

We get the given string from the concatenation of an array of integers arr and the concatenation of all values of the nodes along a path results in a sequence in the given binary tree.

Examples

Example 1:

1
2
3
4
5
6
Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,1,0,1]
Output: true
Explanation: The path 0 -> 1 -> 0 -> 1 is a valid sequence (green color in the figure). 
Other valid sequences are: 
0 -> 1 -> 1 -> 0 
0 -> 0 -> 0

Example 2:

1
2
3
Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,0,1]
Output: false 
Explanation: The path 0 -> 0 -> 1 does not exist, therefore it is not even a sequence.

Example 3:

1
2
3
Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,1,1]
Output: false
Explanation: The path 0 -> 1 -> 1 is a sequence, but it is not a valid sequence.

Constraints:

  • 1 <= arr.length <= 5000
  • 0 <= arr[i] <= 9
  • Each node’s value is between [0 - 9].

Solution

Method 1 – Depth-First Search (DFS) Path Matching

Intuition: We need to check if there exists a root-to-leaf path in the binary tree such that the sequence of node values matches the given array. This is a classic DFS problem where we match the current node’s value with the current index in the array and recursively check the left and right subtrees.

Approach:

  1. Start DFS from the root node and index 0 of the array.
  2. At each node:
    • If the node is null or the index is out of bounds, return false.
    • If the node’s value does not match arr[index], return false.
    • If at a leaf node and index is at the last element of arr, return true.
    • Recursively check left and right children with index + 1.
  3. Return true if any path matches, else false.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution {
public:
    bool isValidSequence(TreeNode* root, vector<int>& arr) {
        return dfs(root, arr, 0);
    }
    bool dfs(TreeNode* node, vector<int>& arr, int idx) {
        if (!node || idx >= arr.size() || node->val != arr[idx]) return false;
        if (!node->left && !node->right && idx == arr.size() - 1) return true;
        return dfs(node->left, arr, idx + 1) || dfs(node->right, arr, idx + 1);
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

func isValidSequence(root *TreeNode, arr []int) bool {
    var dfs func(node *TreeNode, idx int) bool
    dfs = func(node *TreeNode, idx int) bool {
        if node == nil || idx >= len(arr) || node.Val != arr[idx] {
            return false
        }
        if node.Left == nil && node.Right == nil && idx == len(arr)-1 {
            return true
        }
        return dfs(node.Left, idx+1) || dfs(node.Right, idx+1)
    }
    return dfs(root, 0)
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution {
    public boolean isValidSequence(TreeNode root, int[] arr) {
        return dfs(root, arr, 0);
    }
    private boolean dfs(TreeNode node, int[] arr, int idx) {
        if (node == null || idx >= arr.length || node.val != arr[idx]) return false;
        if (node.left == null && node.right == null && idx == arr.length - 1) return true;
        return dfs(node.left, arr, idx + 1) || dfs(node.right, arr, idx + 1);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution {
    fun isValidSequence(root: TreeNode?, arr: IntArray): Boolean {
        fun dfs(node: TreeNode?, idx: Int): Boolean {
            if (node == null || idx >= arr.size || node.`val` != arr[idx]) return false
            if (node.left == null && node.right == null && idx == arr.size - 1) return true
            return dfs(node.left, idx + 1) || dfs(node.right, idx + 1)
        }
        return dfs(root, 0)
    }
}
1
2
3
4
5
6
7
8
9
class Solution:
    def isValidSequence(self, root: 'TreeNode', arr: list[int]) -> bool:
        def dfs(node: 'TreeNode', idx: int) -> bool:
            if not node or idx >= len(arr) or node.val != arr[idx]:
                return False
            if not node.left and not node.right and idx == len(arr) - 1:
                return True
            return dfs(node.left, idx + 1) or dfs(node.right, idx + 1)
        return dfs(root, 0)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
impl Solution {
    pub fn is_valid_sequence(root: Option<Rc<RefCell<TreeNode>>>, arr: Vec<i32>) -> bool {
        fn dfs(node: Option<Rc<RefCell<TreeNode>>>, arr: &Vec<i32>, idx: usize) -> bool {
            if node.is_none() || idx >= arr.len() { return false; }
            let n = node.as_ref().unwrap().borrow();
            if n.val != arr[idx] { return false; }
            if n.left.is_none() && n.right.is_none() && idx == arr.len() - 1 { return true; }
            dfs(n.left.clone(), arr, idx + 1) || dfs(n.right.clone(), arr, idx + 1)
        }
        dfs(root, &arr, 0)
    }
}

Complexity

  • ⏰ Time complexity: O(n), where n is the number of nodes in the tree.
  • 🧺 Space complexity: O(h), where h is the height of the tree (recursion stack).