题目21:1373. 二叉搜索子树的最大键值和
同类题目
前置知识
- 无
题目描述
给你一棵以 root 为根的 二叉树 ,请你返回 任意 二叉搜索子树的最大键值和。
二叉搜索树的定义如下:
- 任意节点的左子树中的键值都 小于 此节点的键值。
- 任意节点的右子树中的键值都 大于 此节点的键值。
- 任意节点的左子树和右子树都是二叉搜索树。
示例 1:
输入:root = [1,4,3,2,4,2,5,null,null,null,null,null,null,4,6]
输出:20
解释:键值为 3 的子树是和最大的二叉搜索树。
示例 2:
输入:root = [4,3,null,1,2]
输出:2
解释:键值为 2 的单节点子树是和最大的二叉搜索树。
示例 3:
输入:root = [-4,-2,-5]
输出:0
解释:所有节点键值都为负数,和最大的二叉搜索树为空。
示例 4:
输入:root = [2,1,3]
输出:6
示例 5:
输入:root = [5,4,8,3,null,6,3]
输出:7
提示:
- 每棵树有
1到40000个节点。 - 每个节点的键值在
[-4 * 10^4 , 4 * 10^4]之间。
思路分析
子问题思路
本题的前置条件是二叉搜索树,判断一颗树是否为二叉搜索树的步骤
- 左右子树为空
- 左子树不为空,并且左子树的最大值小于当前节点值
- 右子树不为空,并且右子树的最小值大于当前节点值
- 左右不为空,并且左子树的最大值小于当前节点值,右子树的最小值大于当前节点值
根据上面的分析,明显发现需要返回左右子树的最大值最小值后,再进行判断。因此,递归位置是后缀位置。
对于树中的每一个节点需要做什么?
递归返回是否是二叉搜索树,如果是需要返回数的和、最大值、最小值。
程序代码
方法一:
// https://leetcode.cn/problems/maximum-sum-bst-in-binary-tree/description/
// 1373. 二叉搜索子树的最大键值和
#include<iostream>
#include<vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
const int M = -0x3f3f3f3f;
class Solution {
private:
int mx = 0;
public:
vector<int> travel(TreeNode *root)
{
// 和,最大值,最小值
vector<int> cur(3,0);
if(root == nullptr)
{
return cur;
}
vector<int> leftv = travel(root->left);
vector<int> rightv = travel(root->right);
// 如果左右子树中任何一棵树不是二叉搜索树,那么当前树也不是二叉搜索树
if(leftv[0] == M || rightv[0] == M)
{
cur[0] = M;
return cur;
}
// 当前节点是否是二叉树搜索树
if(root->left == nullptr && root->right == nullptr)
{
mx = max(mx,root->val);
cur[0] = cur[1] = cur[2] = root->val;
return cur;
}
// 左子树不为空 并且root->left->val < root->val 为二叉搜索树
if(root->left != nullptr && root->right == nullptr && leftv[1] < root->val)
{
mx = max(mx,leftv[0] + root->val);
cur[0] = leftv[0] + root->val;
cur[1] = max(leftv[1],root->val);
cur[2] = min(leftv[2],root->val);
return cur;
}
// 右子树不为空 并且root->right->val > root->val 为二叉搜索树
if(root->left == nullptr && root->right != nullptr && rightv[2] > root->val)
{
mx = max(mx,rightv[0] + root->val);
cur[0] = rightv[0] + root->val;
cur[1] = max(rightv[1],root->val);
cur[2] = min(rightv[2],root->val);
return cur;
}
// 左右都不为空
if(root->left != nullptr && root->right != nullptr && leftv[1] < root->val && rightv[2] > root->val)
{
mx = max(mx,leftv[0] + rightv[0] + root->val);
cur[0] = leftv[0] + rightv[0] + root->val;
cur[1] = max((leftv[1],rightv[1]),root->val);
cur[2] = min(min(leftv[2],rightv[2]),root->val);
return cur;
}
// 其它不是二叉搜索树的时候,返回一个特殊标记值
cur[0] = M;
return cur;
}
int maxSumBST(TreeNode* root) {
travel(root);
cout<<mx<<endl;
return mx;
}
};
复杂度分析
时间复杂度:O(N),一共有 N个节点,每个节点都需要遍历一次。
空间复杂度:O(logN) ,其中logN 为二叉树的高度。
题目感悟
需要子树反馈信息后再计算的基本上就是使用后序遍历。
更多相关知识:github.com/pingguo1987…