💡 This approach improves efficiency by stopping recursion as soon as a valid path is found, avoiding unnecessary exploration.
Intuition
Perform DFS and return true immediately when a path with the target sum is found, pruning the search early.
Algorithm
- Start DFS from root with current sum 0.
- At each node, add node's value to current sum.
- If leaf and sum equals targetSum, return true immediately.
- Recursively check left subtree; if true, return true.
- Otherwise, recursively check right subtree; return true if found.
- If no path found, return false.
💡 The key is to propagate true upwards immediately to avoid exploring unnecessary paths.
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def hasPathSum(root: Optional[TreeNode], targetSum: int) -> bool:
def dfs(node, curr_sum):
if not node:
return False
curr_sum += node.val
if not node.left and not node.right:
return curr_sum == targetSum
return dfs(node.left, curr_sum) or dfs(node.right, curr_sum)
return dfs(root, 0)
# Example usage:
if __name__ == '__main__':
root = TreeNode(5)
root.left = TreeNode(4)
root.right = TreeNode(8)
root.left.left = TreeNode(11)
root.left.left.left = TreeNode(7)
root.left.left.right = TreeNode(2)
root.right.left = TreeNode(13)
root.right.right = TreeNode(4)
root.right.right.right = TreeNode(1)
print(hasPathSum(root, 22)) # True
Line Notes
def dfs(node, curr_sum):Helper function to carry current sum during DFS
if not node:Base case: null node means no path
curr_sum += node.valAdd current node's value to running sum
return dfs(node.left, curr_sum) or dfs(node.right, curr_sum)Return true immediately if any subtree has valid path
public class Solution {
public static class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public boolean hasPathSum(TreeNode root, int targetSum) {
return dfs(root, 0, targetSum);
}
private boolean dfs(TreeNode node, int currSum, int targetSum) {
if (node == null) return false;
currSum += node.val;
if (node.left == null && node.right == null) return currSum == targetSum;
return dfs(node.left, currSum, targetSum) || dfs(node.right, currSum, targetSum);
}
public static void main(String[] args) {
Solution sol = new Solution();
TreeNode root = new TreeNode(5);
root.left = new TreeNode(4);
root.right = new TreeNode(8);
root.left.left = new TreeNode(11);
root.left.left.left = new TreeNode(7);
root.left.left.right = new TreeNode(2);
root.right.left = new TreeNode(13);
root.right.right = new TreeNode(4);
root.right.right.right = new TreeNode(1);
System.out.println(sol.hasPathSum(root, 22)); // true
}
}
Line Notes
return dfs(root, 0, targetSum);Start DFS with initial sum 0
if (node == null) return false;Base case for null node
currSum += node.val;Add node's value to current sum
return dfs(node.left, currSum, targetSum) || dfs(node.right, currSum, targetSum);Return true immediately if any subtree has valid path
#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
bool dfs(TreeNode* node, int currSum, int targetSum) {
if (!node) return false;
currSum += node->val;
if (!node->left && !node->right) return currSum == targetSum;
return dfs(node->left, currSum, targetSum) || dfs(node->right, currSum, targetSum);
}
bool hasPathSum(TreeNode* root, int targetSum) {
return dfs(root, 0, targetSum);
}
int main() {
TreeNode* root = new TreeNode(5);
root->left = new TreeNode(4);
root->right = new TreeNode(8);
root->left->left = new TreeNode(11);
root->left->left->left = new TreeNode(7);
root->left->left->right = new TreeNode(2);
root->right->left = new TreeNode(13);
root->right->right = new TreeNode(4);
root->right->right->right = new TreeNode(1);
cout << boolalpha << hasPathSum(root, 22) << endl; // true
return 0;
}
Line Notes
if (!node) return false;Base case for null node
currSum += node->val;Add current node's value to running sum
if (!node->left && !node->right) return currSum == targetSum;Check if leaf node sum matches targetSum
return dfs(node->left, currSum, targetSum) || dfs(node->right, currSum, targetSum);Return true immediately if any subtree has valid path
function TreeNode(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
function hasPathSum(root, targetSum) {
function dfs(node, currSum) {
if (!node) return false;
currSum += node.val;
if (!node.left && !node.right) return currSum === targetSum;
return dfs(node.left, currSum) || dfs(node.right, currSum);
}
return dfs(root, 0);
}
// Example usage:
const root = new TreeNode(5,
new TreeNode(4,
new TreeNode(11,
new TreeNode(7),
new TreeNode(2)
)
),
new TreeNode(8,
new TreeNode(13),
new TreeNode(4, null, new TreeNode(1))
)
);
console.log(hasPathSum(root, 22)); // true
Line Notes
function dfs(node, currSum) {Helper function to carry current sum
if (!node) return false;Base case for null node
currSum += node.val;Add node's value to running sum
return dfs(node.left, currSum) || dfs(node.right, currSum);Return true immediately if any subtree has valid path
Each node is visited once, and recursion stack depth is at most tree height h.
💡 For a tree with 1000 nodes and height 10, expect about 1000 operations and stack depth up to 10.
Interview Verdict: Accepted
Early stopping can save time in practice but asymptotic complexity remains the same.