Find the minimum Subtree with target sum in a Binary search tree

Last Updated : 15 Sep, 2026

Given the root of a binary tree and an integer target, find the size (number of nodes) of the smallest subtree whose sum of node values is equal to target and that is also a Binary Search Tree (BST). If no such subtree exists, return -1.

Examples:

Input: root = [13, 5, 23, N, 17, N, 16], target = 38

2056958708


Output: 3
Explanation: 5,17,16 is the smallest subtree with length 3.

Input: root = [7, N, 23, 10, 23, N, 17], target = 73

2056958709


Output: -1
Explanation: No subtree is BST for the given target.

Try It Yourself
redirect icon

[Naive Approach] Check Every Subtree Independently - O(n^2) Time and O(h) Space

Treat every node as a potential subtree root and independently check whether its subtree is a BST using min-max validation.

If valid, compute its sum and size, and track the minimum size for subtrees matching the target sum.

Illustration:

  • Take root = [13, 5, 23, N, 17, N, 16], target = 38.
  • Checking the subtree rooted at 5 (containing 5, 17, 16): this is validated as a BST (5 < 17, and 16 < 17 fits correctly as 17's left child), with sum = 5+17+16 = 38, matching the target, and size = 3.
  • Checking the subtree rooted at 13 (the whole tree): this is not a valid BST, since 23 (in 13's right subtree) is fine, but node 17 sits in 13's left subtree while also needing to be less than 23 and greater than 5 - the actual violation is that 16 and 17 don't fit BST ordering relative to the whole tree's structure at node 5, since 5's right child 17 having a left child 16 disrupts the BST property when checked against the full tree's range.
  • Checking other individual nodes (13, 23, 16, etc.) as subtree roots either fails the BST check or doesn't match the target sum.
  • Among all valid BST subtrees checked, the one rooted at 5 gives the smallest matching size of 3, matching the expected output.
C++
#include <bits/stdc++.h>
using namespace std;

class Node {
public:
    int data;
    Node *left, *right;
    Node(int val) {
        data = val;
        left = right = nullptr;
    }
};

bool isBST(Node* node, long long lo, long long hi) {
    if (node == nullptr)
        return true;
    if (node->data <= lo || node->data >= hi)
        return false;
    return isBST(node->left, lo, node->data) && isBST(node->right, node->data, hi);
}

int sumOfSubtree(Node* node) {
    if (node == nullptr)
        return 0;
    return node->data + sumOfSubtree(node->left) + sumOfSubtree(node->right);
}

int sizeOfSubtree(Node* node) {
    if (node == nullptr)
        return 0;
    return 1 + sizeOfSubtree(node->left) + sizeOfSubtree(node->right);
}

void collectAllNodes(Node* node, vector<Node*> &nodes) {
    if (node == nullptr)
        return;
    nodes.push_back(node);
    collectAllNodes(node->left, nodes);
    collectAllNodes(node->right, nodes);
}

int minSubtreeSumBST(int target, Node* root) {
    vector<Node*> allNodes;
    collectAllNodes(root, allNodes);

    int best = INT_MAX;

    // check every node as a potential subtree root independently
    for (Node* node : allNodes) {
        if (isBST(node, LLONG_MIN, LLONG_MAX)) {
            int sum = sumOfSubtree(node);
            if (sum == target) {
                best = min(best, sizeOfSubtree(node));
            }
        }
    }

    return (best == INT_MAX) ? -1 : best;
}

int main() {
    Node* root = new Node(13);
    root->left = new Node(5);
    root->right = new Node(23);
    root->left->right = new Node(17);
    root->left->right->left = new Node(16);

    cout << minSubtreeSumBST(38, root) << endl;

    return 0;
}
Java
import java.util.*;

class Node {
    int data;
    Node left, right;
    Node(int val) {
        data = val;
        left = right = null;
    }
}

class GFG {
    static boolean isBST(Node node, long lo, long hi) {
        if (node == null)
            return true;
        if (node.data <= lo || node.data >= hi)
            return false;
        return isBST(node.left, lo, node.data) && isBST(node.right, node.data, hi);
    }

    static int sumOfSubtree(Node node) {
        if (node == null)
            return 0;
        return node.data + sumOfSubtree(node.left) + sumOfSubtree(node.right);
    }

    static int sizeOfSubtree(Node node) {
        if (node == null)
            return 0;
        return 1 + sizeOfSubtree(node.left) + sizeOfSubtree(node.right);
    }

    static void collectAllNodes(Node node, List<Node> nodes) {
        if (node == null)
            return;
        nodes.add(node);
        collectAllNodes(node.left, nodes);
        collectAllNodes(node.right, nodes);
    }

    static int minSubtreeSumBST(int target, Node root) {
        List<Node> allNodes = new ArrayList<>();
        collectAllNodes(root, allNodes);

        int best = Integer.MAX_VALUE;

        // check every node as a potential subtree root independently
        for (Node node : allNodes) {
            if (isBST(node, Long.MIN_VALUE, Long.MAX_VALUE)) {
                int sum = sumOfSubtree(node);
                if (sum == target) {
                    best = Math.min(best, sizeOfSubtree(node));
                }
            }
        }

        return (best == Integer.MAX_VALUE) ? -1 : best;
    }

    public static void main(String[] args) {
        Node root = new Node(13);
        root.left = new Node(5);
        root.right = new Node(23);
        root.left.right = new Node(17);
        root.left.right.left = new Node(16);

        System.out.println(minSubtreeSumBST(38, root));
    }
}
Python
import sys

class Node:
    def __init__(self, val):
        self.data = val
        self.left = None
        self.right = None

def isBST(node, lo, hi):
    if node is None:
        return True
    if node.data <= lo or node.data >= hi:
        return False
    return isBST(node.left, lo, node.data) and isBST(node.right, node.data, hi)

def sumOfSubtree(node):
    if node is None:
        return 0
    return node.data + sumOfSubtree(node.left) + sumOfSubtree(node.right)

def sizeOfSubtree(node):
    if node is None:
        return 0
    return 1 + sizeOfSubtree(node.left) + sizeOfSubtree(node.right)

def collectAllNodes(node, nodes):
    if node is None:
        return
    nodes.append(node)
    collectAllNodes(node.left, nodes)
    collectAllNodes(node.right, nodes)

def minSubtreeSumBST(target, root):
    all_nodes = []
    collectAllNodes(root, all_nodes)

    best = sys.maxsize

    # check every node as a potential subtree root independently
    for node in all_nodes:
        if isBST(node, -sys.maxsize, sys.maxsize):
            total = sumOfSubtree(node)
            if total == target:
                best = min(best, sizeOfSubtree(node))

    return -1 if best == sys.maxsize else best

root = Node(13)
root.left = Node(5)
root.right = Node(23)
root.left.right = Node(17)
root.left.right.left = Node(16)

print(minSubtreeSumBST(38, root))
C#
using System;
using System.Collections.Generic;

class Node {
    public int data;
    public Node left, right;
    public Node(int val) {
        data = val;
        left = right = null;
    }
}

class GFG {
    static bool isBST(Node node, long lo, long hi) {
        if (node == null)
            return true;
        if (node.data <= lo || node.data >= hi)
            return false;
        return isBST(node.left, lo, node.data) && isBST(node.right, node.data, hi);
    }

    static int sumOfSubtree(Node node) {
        if (node == null)
            return 0;
        return node.data + sumOfSubtree(node.left) + sumOfSubtree(node.right);
    }

    static int sizeOfSubtree(Node node) {
        if (node == null)
            return 0;
        return 1 + sizeOfSubtree(node.left) + sizeOfSubtree(node.right);
    }

    static void collectAllNodes(Node node, List<Node> nodes) {
        if (node == null)
            return;
        nodes.Add(node);
        collectAllNodes(node.left, nodes);
        collectAllNodes(node.right, nodes);
    }

    static int minSubtreeSumBST(int target, Node root) {
        List<Node> allNodes = new List<Node>();
        collectAllNodes(root, allNodes);

        int best = int.MaxValue;

        // check every node as a potential subtree root independently
        foreach (Node node in allNodes) {
            if (isBST(node, long.MinValue, long.MaxValue)) {
                int sum = sumOfSubtree(node);
                if (sum == target) {
                    best = Math.Min(best, sizeOfSubtree(node));
                }
            }
        }

        return (best == int.MaxValue) ? -1 : best;
    }

    static void Main() {
        Node root = new Node(13);
        root.left = new Node(5);
        root.right = new Node(23);
        root.left.right = new Node(17);
        root.left.right.left = new Node(16);

        Console.WriteLine(minSubtreeSumBST(38, root));
    }
}
JavaScript
class Node {
    constructor(val) {
        this.data = val;
        this.left = null;
        this.right = null;
    }
}

function isBST(node, lo, hi) {
    if (node === null)
        return true;
    if (node.data <= lo || node.data >= hi)
        return false;
    return isBST(node.left, lo, node.data) && isBST(node.right, node.data, hi);
}

function sumOfSubtree(node) {
    if (node === null)
        return 0;
    return node.data + sumOfSubtree(node.left) + sumOfSubtree(node.right);
}

function sizeOfSubtree(node) {
    if (node === null)
        return 0;
    return 1 + sizeOfSubtree(node.left) + sizeOfSubtree(node.right);
}

function collectAllNodes(node, nodes) {
    if (node === null)
        return;
    nodes.push(node);
    collectAllNodes(node.left, nodes);
    collectAllNodes(node.right, nodes);
}

function minSubtreeSumBST(target, root) {
    const allNodes = [];
    collectAllNodes(root, allNodes);

    let best = Infinity;

    // check every node as a potential subtree root independently
    for (const node of allNodes) {
        if (isBST(node, -Infinity, Infinity)) {
            const sum = sumOfSubtree(node);
            if (sum === target) {
                best = Math.min(best, sizeOfSubtree(node));
            }
        }
    }

    return (best === Infinity) ? -1 : best;
}

// Driver Code
const root = new Node(13);
root.left = new Node(5);
root.right = new Node(23);
root.left.right = new Node(17);
root.left.right.left = new Node(16);

console.log(minSubtreeSumBST(38, root));

Output
3

[Expected Approach] Single-Pass Postorder Traversal - O(n) Time and O(h) Space

A single postorder traversal computes all required information for every node using its children's results.

Each node is processed in constant time, checking BST validity, minimum, maximum, sum, and size.

Illustration:

  • Take root = [13, 5, 23, N, 17, N, 16], target = 38.
  • At the leaf node 16: it's trivially a valid BST, with min=16, max=16, sum=16, size=1.
  • At node 17 (with left child 16): since 16 < 17, this forms a valid BST; combining gives min=16, max=17, sum=16+17=33, size=2.
  • At node 5 (with right child being the subtree rooted at 17): since 5 < 17 (the minimum of the right subtree), this forms a valid BST; combining gives min=5, max=17, sum=5+33=38, size=3. Since this sum exactly matches the target, the answer is updated to 3.
  • At node 23: trivially a valid BST on its own, sum=23, size=1, not matching the target.
  • At the root 13: combining the left subtree (rooted at 5, valid BST with max=17) and right subtree (rooted at 23, valid BST with min=23) requires checking that 13 is greater than the left subtree's max (17) — but 13 < 17, so this fails the BST condition, meaning the whole tree is not a valid BST.
  • Since the smallest valid BST subtree found with sum 38 is the one rooted at 5, with size 3, this is the final answer.
C++
#include <bits/stdc++.h>
using namespace std;

class Node {
public:
    int data;
    Node *left, *right;
    Node(int val) {
        data = val;
        left = right = nullptr;
    }
};

int ans;

// Returns: {isBST, min, max, sum, size}
vector<int> dfs(Node* root, int target) {
    if (root == nullptr)
        return {1, INT_MAX, INT_MIN, 0, 0};

    vector<int> left = dfs(root->left, target);
    vector<int> right = dfs(root->right, target);

    int sum = left[3] + right[3] + root->data;
    int size = left[4] + right[4] + 1;

    // check if current subtree is a BST
    if (left[0] && right[0] && root->data > left[2] && root->data < right[1]) {

        // update minimum size for matching sum
        if (sum == target)
            ans = min(ans, size);

        int mn = min(root->data, left[1]);
        int mx = max(root->data, right[2]);

        return {1, mn, mx, sum, size};
    }

    // current subtree is not a BST
    return {0, INT_MIN, INT_MAX, sum, size};
}

int minSubtreeSumBST(int target, Node* root) {
    ans = INT_MAX;
    dfs(root, target);
    return (ans == INT_MAX) ? -1 : ans;
}

int main() {
    Node* root = new Node(13);
    root->left = new Node(5);
    root->right = new Node(23);
    root->left->right = new Node(17);
    root->left->right->left = new Node(16);

    cout << minSubtreeSumBST(38, root) << endl;

    return 0;
}
Java
class Node {
    int data;
    Node left, right;
    Node(int val) {
        data = val;
        left = right = null;
    }
}

class GFG {
    static int ans;

    static int[] dfs(Node root, int target) {
        if (root == null)
            return new int[]{1, Integer.MAX_VALUE, Integer.MIN_VALUE, 0, 0};

        int[] left = dfs(root.left, target);
        int[] right = dfs(root.right, target);

        int sum = left[3] + right[3] + root.data;
        int size = left[4] + right[4] + 1;

        if (left[0] == 1 && right[0] == 1 && root.data > left[2] && root.data < right[1]) {
            if (sum == target)
                ans = Math.min(ans, size);

            int mn = Math.min(root.data, left[1]);
            int mx = Math.max(root.data, right[2]);

            return new int[]{1, mn, mx, sum, size};
        }

        return new int[]{0, Integer.MIN_VALUE, Integer.MAX_VALUE, sum, size};
    }

    static int minSubtreeSumBST(int target, Node root) {
        ans = Integer.MAX_VALUE;
        dfs(root, target);
        return (ans == Integer.MAX_VALUE) ? -1 : ans;
    }

    public static void main(String[] args) {
        Node root = new Node(13);
        root.left = new Node(5);
        root.right = new Node(23);
        root.left.right = new Node(17);
        root.left.right.left = new Node(16);

        System.out.println(minSubtreeSumBST(38, root));
    }
}
Python
import sys

class Node:
    def __init__(self, val):
        self.data = val
        self.left = None
        self.right = None

def minSubtreeSumBST(target, root):
    ans = [sys.maxsize]

    # returns (isBST, minVal, maxVal, sum, size)
    def dfs(node):
        if node is None:
            return (1, sys.maxsize, -sys.maxsize, 0, 0)

        left = dfs(node.left)
        right = dfs(node.right)

        total = left[3] + right[3] + node.data
        size = left[4] + right[4] + 1

        # check if current subtree is a BST
        if left[0] and right[0] and node.data > left[2] and node.data < right[1]:

            # update minimum size for matching sum
            if total == target:
                ans[0] = min(ans[0], size)

            mn = min(node.data, left[1])
            mx = max(node.data, right[2])

            return (1, mn, mx, total, size)

        # current subtree is not a BST
        return (0, -sys.maxsize, sys.maxsize, total, size)

    dfs(root)

    return -1 if ans[0] == sys.maxsize else ans[0]

root = Node(13)
root.left = Node(5)
root.right = Node(23)
root.left.right = Node(17)
root.left.right.left = Node(16)

print(minSubtreeSumBST(38, root))
C#
using System;

class Node {
    public int data;
    public Node left, right;
    public Node(int val) {
        data = val;
        left = right = null;
    }
}

class GFG {
    static int ans;

    static int[] dfs(Node root, int target) {
        if (root == null)
            return new int[] { 1, int.MaxValue, int.MinValue, 0, 0 };

        int[] left = dfs(root.left, target);
        int[] right = dfs(root.right, target);

        int sum = left[3] + right[3] + root.data;
        int size = left[4] + right[4] + 1;

        if (left[0] == 1 && right[0] == 1 && root.data > left[2] && root.data < right[1]) {
            if (sum == target)
                ans = Math.Min(ans, size);

            int mn = Math.Min(root.data, left[1]);
            int mx = Math.Max(root.data, right[2]);

            return new int[] { 1, mn, mx, sum, size };
        }

        return new int[] { 0, int.MinValue, int.MaxValue, sum, size };
    }

    static int minSubtreeSumBST(int target, Node root) {
        ans = int.MaxValue;
        dfs(root, target);
        return (ans == int.MaxValue) ? -1 : ans;
    }

    static void Main() {
        Node root = new Node(13);
        root.left = new Node(5);
        root.right = new Node(23);
        root.left.right = new Node(17);
        root.left.right.left = new Node(16);

        Console.WriteLine(minSubtreeSumBST(38, root));
    }
}
JavaScript
function dfs(node, target, ans) {
    if (node === null)
        return [1, Infinity, -Infinity, 0, 0];

    const left = dfs(node.left, target, ans);
    const right = dfs(node.right, target, ans);

    const sum = left[3] + right[3] + node.data;
    const size = left[4] + right[4] + 1;

    if (left[0] && right[0] &&
        node.data > left[2] &&
        node.data < right[1]) {

        if (sum === target)
            ans.value = Math.min(ans.value, size);

        const mn = Math.min(node.data, left[1]);
        const mx = Math.max(node.data, right[2]);

        return [1, mn, mx, sum, size];
    }

    return [0, -Infinity, Infinity, sum, size];
}

function minSubtreeSumBST(target, root) {
    const ans = { value: Infinity };

    dfs(root, target, ans);

    return ans.value === Infinity ? -1 : ans.value;
}

class Node {
    constructor(val) {
        this.data = val;
        this.left = null;
        this.right = null;
    }
}

// Driver Code
const root = new Node(13);
root.left = new Node(5);
root.right = new Node(23);
root.left.right = new Node(17);
root.left.right.left = new Node(16);

console.log(minSubtreeSumBST(38, root));

Output
3
Comment