🧠
Optimized DFS with BST Pruning
💡 This approach improves efficiency by leveraging BST properties to skip subtrees that cannot contain values in the range.
Intuition
If the current node's value is less than low, then all nodes in its left subtree are also less and can be skipped. Similarly, if the node's value is greater than high, skip the right subtree.
Algorithm
- Start at the root node.
- If node is null, return 0.
- If node's value is less than low, recurse only on right subtree.
- If node's value is greater than high, recurse only on left subtree.
- Otherwise, add node's value and recurse on both subtrees.
💡 The key insight is pruning entire subtrees to reduce unnecessary work.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def rangeSumBST(root, low, high):
if not root:
return 0
if root.val < low:
return rangeSumBST(root.right, low, high)
if root.val > high:
return rangeSumBST(root.left, low, high)
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high)
# Example usage:
if __name__ == '__main__':
root = TreeNode(10, TreeNode(5, TreeNode(3), TreeNode(7)), TreeNode(15, None, TreeNode(18)))
print(rangeSumBST(root, 7, 15)) # Output: 32
Line Notes
if not root:Base case to stop recursion at null nodes.
if root.val < low:Skip left subtree because all values there are smaller than low.
if root.val > high:Skip right subtree because all values there are greater than high.
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high)Add current node and recurse both sides if within range.
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public int rangeSumBST(TreeNode root, int low, int high) {
if (root == null) return 0;
if (root.val < low) return rangeSumBST(root.right, low, high);
if (root.val > high) return rangeSumBST(root.left, low, high);
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high);
}
public static void main(String[] args) {
TreeNode root = new TreeNode(10);
root.left = new TreeNode(5);
root.right = new TreeNode(15);
root.left.left = new TreeNode(3);
root.left.right = new TreeNode(7);
root.right.right = new TreeNode(18);
Solution sol = new Solution();
System.out.println(sol.rangeSumBST(root, 7, 15)); // 32
}
}
Line Notes
if (root == null) return 0;Stop recursion at null nodes.
if (root.val < low) return rangeSumBST(root.right, low, high);Skip left subtree when node value less than low.
if (root.val > high) return rangeSumBST(root.left, low, high);Skip right subtree when node value greater than high.
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high);Add current node and recurse both subtrees if in range.
#include <iostream>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
class Solution {
public:
int rangeSumBST(TreeNode* root, int low, int high) {
if (!root) return 0;
if (root->val < low) return rangeSumBST(root->right, low, high);
if (root->val > high) return rangeSumBST(root->left, low, high);
return root->val + rangeSumBST(root->left, low, high) + rangeSumBST(root->right, low, high);
}
};
int main() {
TreeNode* root = new TreeNode(10);
root->left = new TreeNode(5);
root->right = new TreeNode(15);
root->left->left = new TreeNode(3);
root->left->right = new TreeNode(7);
root->right->right = new TreeNode(18);
Solution sol;
cout << sol.rangeSumBST(root, 7, 15) << endl; // 32
return 0;
}
Line Notes
if (!root) return 0;Stop recursion at null nodes.
if (root->val < low) return rangeSumBST(root->right, low, high);Skip left subtree if node value less than low.
if (root->val > high) return rangeSumBST(root->left, low, high);Skip right subtree if node value greater than high.
return root->val + rangeSumBST(root->left, low, high) + rangeSumBST(root->right, low, high);Add current node and recurse both subtrees if in range.
function TreeNode(val, left = null, right = null) {
this.val = val;
this.left = left;
this.right = right;
}
function rangeSumBST(root, low, high) {
if (!root) return 0;
if (root.val < low) return rangeSumBST(root.right, low, high);
if (root.val > high) return rangeSumBST(root.left, low, high);
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high);
}
// Example usage:
const root = new TreeNode(10,
new TreeNode(5, new TreeNode(3), new TreeNode(7)),
new TreeNode(15, null, new TreeNode(18))
);
console.log(rangeSumBST(root, 7, 15)); // 32
Line Notes
if (!root) return 0;Base case to stop recursion at null nodes.
if (root.val < low) return rangeSumBST(root.right, low, high);Skip left subtree if node value less than low.
if (root.val > high) return rangeSumBST(root.left, low, high);Skip right subtree if node value greater than high.
return root.val + rangeSumBST(root.left, low, high) + rangeSumBST(root.right, low, high);Add current node and recurse both subtrees if in range.
TimeO(n) in worst case, O(log n) average
SpaceO(h)
In worst case (skewed tree), we visit all nodes. Average case prunes subtrees, reducing nodes visited to O(log n).
💡 For balanced trees with 1000 nodes, this approach visits far fewer nodes than brute force.
Interview Verdict: Accepted and efficient
This approach is preferred in interviews because it uses BST properties to optimize traversal.