[LeetCode] 1373. Maximum Sum BST in Binary Tree 二叉搜索子树的最大键值和
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
类似题目:
Binary Tree Postorder Traversal
Find Mode in Binary Search Tree
参考资料:
https://leetcode.com/problems/maximum-sum-bst-in-binary-tree


浙公网安备 33010602011771号