惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
博客园 - 司徒正美
博客园 - 【当耐特】
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
IT之家
IT之家
人人都是产品经理
人人都是产品经理
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
宝玉的分享
宝玉的分享
V
V2EX
S
SegmentFault 最新的问题
V
Visual Studio Blog
阮一峰的网络日志
阮一峰的网络日志
Martin Fowler
Martin Fowler
Jina AI
Jina AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
L
LangChain Blog
D
Docker
腾讯CDC

博客园 - Grandyang

[LeetCode] 1375. Number of Times Binary String Is Prefix-Aligned 二进制字符串前缀一致的次数 [LeetCode] 1374. Generate a String With Characters That Have Odd Counts 生成每种字符都是奇数个的字符串 [LeetCode] 1372. Longest ZigZag Path in a Binary Tree 二叉树中的最长交错路径 [LeetCode] 1371. Find the Longest Substring Containing Vowels in Even Counts 每个元音包含偶数次的最长子字符串 [LeetCode] 1370. Increasing Decreasing String 上升下降字符串 [LeetCode] 1368. Minimum Cost to Make at Least One Valid Path in a Grid 使网格图至少有一条有效路径的最小代价 [LeetCode] 1367. Linked List in Binary Tree 二叉树中的链表 [LeetCode] 1366. Rank Teams by Votes 通过投票对团队排名 [LeetCode] 1365. How Many Numbers Are Smaller Than the Current Number 有多少小于当前数字的数字 [LeetCode] 1363. Largest Multiple of Three 形成三的最大倍数 [LeetCode] 1362. Closest Divisors 最接近的因数 [LeetCode] 1361. Validate Binary Tree Nodes 验证二叉树 [LeetCode] 1360. Number of Days Between Two Dates 日期之间隔几天 [LeetCode] 1359. Count All Valid Pickup and Delivery Options 有效的快递序列数目 [LeetCode] 1358. Number of Substrings Containing All Three Characters 包含所有三种字符的子字符串数目 [LeetCode] 1357. Apply Discount Every n Orders 每隔n个顾客打折 [LeetCode] 1356. Sort Integers by The Number of 1 Bits 根据数字二进制下1 的数目排序 [LeetCode] 1354. Construct Target Array With Multiple Sums 多次求和构造目标数组 [LeetCode] 1353. Maximum Number of Events That Can Be Attended 最多可以参加的会议数目 [LeetCode] 1352. Product of the Last K Numbers 最后 K 个数的乘积 [LeetCode] 1351. Count Negative Numbers in a Sorted Matrix 统计有序矩阵中的负数 [LeetCode] 1349. Maximum Students Taking Exam 参加考试的最大学生数
[LeetCode] 1373. Maximum Sum BST in Binary Tree 二叉搜索...
Grandyang · 2026-08-23 · via 博客园 - Grandyang

Given a binary tree `root`, return *the maximum sum of all keys of any sub-tree which is also a Binary Search Tree (BST)*.

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less than the node's key.
  • The right subtree of a node contains only nodes with keys greater than the node's key.
  • Both the left and right subtrees must also be binary search trees.

Example 1:

Input: root = [1,4,3,2,4,2,5,null,null,null,null,null,null,4,6]
Output: 20
Explanation: Maximum sum in a valid Binary search tree is obtained in root node with key equal to 3.

Example 2:

Input: root = [4,3,null,1,2]
Output: 2
Explanation: Maximum sum in a valid Binary search tree is obtained in a single root node with key equal to 2.

Example 3:

Input: root = [-4,-2,-5]
Output: 0
Explanation: All values are negatives. Return an empty BST.

Constraints:

  • The number of nodes in the tree is in the range [1, 4 * 10^4].
  • -4 * 10^4 <= Node.val <= 4 * 10^4

这道题说是给了一个二叉树,让找出子树中最大的二叉搜索树 Binary Search Tree (BST),并返回该子树的所有结点之和。这道题又是关于二叉搜索树的题,BST 也算是我们的老朋友了,LeetCdoe 上相关题目少说也有二十多道了,想必大家也并不陌生了。核心的一点就是当前的结点值一定要大于左子树中的最大值,一定要小于右子树中的最小值,并且左右子树都必须也要是 BST。关于验证 BST 的题目可以参见之前这道 Validate Binary Search Tree,其核心思想就是利用递归写法的中序遍历去验证 左<根<右 的这条性质。这道题并不是简单的要去验证 BST,而是要找到最大的子二叉搜索树,就是说关注点就在子树这里,那么天然适合用后序遍历去做,为啥呢,因为后序遍历是左右根的顺序,先遍历左右子结点,最后才是根结点,等到根结点的时候,左右子树的信息都已经有了,不管是统计子树的结点个数,还是结点之和都很方便了。

其实跟这道题最像的是之前的那道 Largest BST Subtree,求的就是最大 BST 子树的结点的个数,只不过这里换成了结点之和。这里还是采用递归写法的后序遍历来做,使用一个全局变量 res 来记录遍历过程中最大的 BST 子树的结点之和。这里使用的递归的子函数的返回值是一个长度为3的数组,三个值分别是当前 BST 子树中的最小值,最大值,还有结点之和。这三个信息都是特别重要的,缺一不可,最大值和最小值是持续验证子树是否是 BST 的关键,而结点之和是用来更新全局 res 的值的。在递归函数中,首先判空,如果当前结点为空,则返回默认的三个值,整型数最大值,整型数最小值,和0,特别要注意的就是这里的第一个数字我们定义的是子树中的最小值,而这里却要传整型数的最大值,这是为啥呢,后面会解释。接下来就是后序遍历的传统写法,先对左右子结点调用递归函数,将返回的数组分别存在 left 和 right 数组变量中。

然后就是关键的验证 BST 的步骤了,对于不是 BST 子树的根结点,返回数组会为空,这样的话,只要判断 left 或者 right 为空,就表示当前根结点的左子树或者右子树不是 BST,则当前二叉树也不是 BST。若 left 和 right 不为空,还要继续验证 左<根<右 的这条性质。左子树的最大值存在了 left[1] 中,若根结点小于等于 left[1],则当前二叉树不是 BST,同理,右子树的最小值存在了 right[0] 中,若根结点大于等于 right[0],则当前二叉树也不是 BST,返回空数组即可。这里回过头说一下为啥遇到空结点,要把整型数最大值放到第一个,整型数最小值放在第二个位置。当左子结点不存在的时候,左子树最大值 left[1] 设置为整型数最小值,当前根结点一定会大于这个整型数最小值,同理,当右子结点不存在时,右子树最小值 right[0] 设置为整型数最大值,当前根结点一定会小于这个整型数最大值,整个逻辑不用变,都可以通过。

经过了 BST 性质的验证,则当前子树是 BST,计算当前子树的结点之和,用根结点的值加上 left[2] 和 right[2] 即可,然后用 sum 更新最终结果 res 的值。接下来计算当前子树的最小值 mn,取根结点值和 left[0] 中的较小值,同理,当前子树的最大值 mx,取根结点值和 right[1] 中的较大值,将 mn, mx 和 sum 组成一个数组返回即可,参见代码如下:


class Solution {
public:
    int maxSumBST(TreeNode* root) {
        int res = 0;
        dfs(root, res);
        return res;
    }
    vector<int> dfs(TreeNode* node, int& res) {
        if (!node) return {INT_MAX, INT_MIN, 0};
        vector<int> left = dfs(node->left, res);
        vector<int> right = dfs(node->right, res);
        if(left.empty() || right.empty() || node->val <= left[1] || node->val >= right[0]) {
            return {};
        }
        int sum = node->val + left[2] + right[2];
        res = max(res, sum);
        int mn = min(node->val, left[0]);
        int mx = max(node->val, right[1]);
        return {mn, mx, sum};
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/1373

类似题目:

Validate Binary Search Tree

Binary Tree Postorder Traversal

Find Mode in Binary Search Tree

Largest BST Subtree

参考资料:

https://leetcode.com/problems/maximum-sum-bst-in-binary-tree

https://leetcode.com/problems/maximum-sum-bst-in-binary-tree/solutions/531822/java-post-order-traverse-with-comment-cl-f0vl/

https://leetcode.com/problems/maximum-sum-bst-in-binary-tree/solutions/1126183/c-recursion-easy-to-understand-by-divyan-6fa0/

LeetCode All in One 题目讲解汇总(持续更新中...)