Problem

Given a Binary Search Tree (BST) keyed on positive integers, find the shortest path (a sequence of connected nodes) in the tree such that the sum of the keys in the path adds up to a given integer K. If no such path exists, return an appropriate message indicating that no path is found. Each path must originate from the root of the tree and may terminate at any node such that the cumulative sum equals K.

Examples

Example 1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Input: 
          10
        /    \
       7      15
      / \     /  \
     5   9   12   20
    /       / \
   3       11  13

               
       K = 25
 
Output: [10, 15]

Explanation: 
Path 1: 10  7  9; Cumulative Sum = 10 + 7 + 9 = 26 (Not valid as it exceeds 25).
Path 2: 10  15; Cumulative Sum = 10 + 15 = 25. Path Length = 2.
Path 3: 10  7  5  3; Cumulative Sum = 10 + 7 + 5 + 3 = 25. Path Length = 4.

We choose path 2 as it is the shortest.

Example 2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Input: 
       Tree:        10
                  /    \
                 6      15
                / \    /   \
               3   8  12   20
               
       K = 25
 
Output: [10, 15]

Explanation: 
The path 10  15 sums up to 25, which is the shortest path for the given 

Solution

Method 1 - DFS

Reasoning or Intuition

Imagine we have a target number K, and we want to identify the smallest possible set of numbers (path) in a Binary Search Tree (BST) that sum up to K. The goal is to find the shortest sequence of connected nodes that adds up to this target.

Let us consider an example where K = 25 for the given BST:

1
2
3
4
5
6
7
          10
        /    \
       7      15
      / \     /  \
     5   9   12   20
    /       / \
   3       11  13

There are two possible paths that sum up to 25:

  1. Path 110 → 15
    • Cumulative sum = 10 + 15 = 25.
    • Path length = 2.
  2. Path 210 → 7 → 5 → 3
    • Cumulative sum = 10 + 7 + 5 + 3 = 25.
    • Path length = 4.

Both paths achieve the target sum, but clearly, Path 1 is shorter (length = 2), so it is the preferred solution. The requirement is to find a path that achieves the desired sum while minimising the number of nodes in the sequence.

Key Observation

In a Binary Search Tree:

  • Larger numbers are typically located in the right subtrees, while smaller numbers are located in the left subtrees.
  • As summing larger numbers reduces the number of nodes needed to reach the target sum, exploring the right subtree preferentially can often produce shorter paths.

Consider the following principle:

  • If we first explore the right subtree, we may find shorter paths summing to K due to the presence of larger values.
  • If no valid path is found on the right, we then shift to evaluating the left subtree.
  • If the cumulative sum exceeds K during traversal, further exploration of that path is unnecessary, as additional nodes will only increase the sum.

Approach

To solve this problem efficiently:

  1. Prioritise Right Subtrees: Start investigating the right subtrees first, as they often contain larger values.
  2. Use Recursive Backtracking: Track the cumulative sum and the path so far, and compare results with the shortest valid path.
  3. Terminate Suboptimal Paths: If the cumulative sum exceeds K, stop exploring that branch to save computational effort.
  4. Compare and Update: Whenever a valid path sums to K, check if its length is smaller than the shortest known path. If it is, update the result.
  5. Fallback to Left Subtrees: If no valid path exists on the right, shift exploration to left subtrees.

Code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Solution {

    // Definition for a binary tree node
    static class TreeNode {

        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int val) {
            this.val = val;
        }
    }

    // Function to create duplicate nodes
    public void duplicateTree(TreeNode root) {
        if (root == null) {
            return;
        }

        // Create duplicate node
        TreeNode duplicate = new TreeNode(root.val);

        // Attach duplicate as the left child
        duplicate.left = root.left;
        root.left = duplicate;

        // Recursive calls for original left and right children
        duplicateTree(duplicate.left);
        duplicateTree(root.right);
    }

    // Helper function to print tree (inorder traversal)
    public void print(TreeNode root) {
        if (root == null) return;
        print(root.left);
        System.out.print(root.val + " ");
        print(root.right);
    }

    public static void main(String[] args) {
        Solution sol = new Solution();

        TreeNode root = new TreeNode(2);
        root.left = new TreeNode(1);
        root.right = new TreeNode(3);

        System.out.println("Original Tree:");
        sol.print(root);

        // Transform
        sol.duplicateTree(root);

        System.out.println("\nTransformed Tree:");
        sol.print(root);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution:
    def duplicateTree(self, root):
        if root is None:
            return

        # Create duplicate node
        duplicate = TreeNode(root.val)

        # Attach duplicate as the left child
        duplicate.left = root.left
        root.left = duplicate

        # Recursive calls for original left and right children
        self.duplicateTree(duplicate.left)
        self.duplicateTree(root.right)

    def printTree(self, root):
        # Helper function to print the tree (inorder traversal)
        if root is None:
            return
        self.printTree(root.left)
        print(root.val, end=" ")
        self.printTree(root.right)


# Driver code
if __name__ == "__main__":
    solution = Solution()

    # Example tree
    root = TreeNode(2)
    root.left = TreeNode(1)
    root.right = TreeNode(3)

    print("Original Tree:")
    solution.printTree(root)

    # Transform the tree
    solution.duplicateTree(root)

    print("\nTransformed Tree:")
    solution.printTree(root)

Complexity

  • ⏰ Time complexity: O(n). Every node in the tree is visited once, where n is the number of nodes.

  • 🧺 Space complexity: O(h). The recursion stack depth is proportional to the height of the tree, which is h (logarithmic for a balanced BST, and O(N) for a skewed tree).