力扣5339 二叉搜索子树的最大键值和 解题报告

题目描述

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

给你一棵以 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

提示:

每棵树最多有 40000 个节点。
每个节点的键值在 [-4 * 10^4 , 4 * 10^4] 之间。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-sum-bst-in-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路分析

这道题比较麻烦的一点是要判断这棵树是不是二叉搜索树。这里我借(chao)鉴(xi)了大佬的做法。这里我们用到了树形dp的做法:先向子树进行递归,递归的过程中判断自己的左右儿子符不符合二叉搜索树的条件。返回的时候,需要返回四个状态:自己符不符合二叉搜索树?目前我这个子树上的最大键值是多少?最小键值是多少(用于给自己的根节点判断符不符合二叉搜索树)?现在的键值和是多少?这里大佬有个技巧:如果需要返回多个值,可以选择返回一个vector记录这些状态。另外,需要要注意遇到NULL节点时的处理。

ac代码

int ans=0;
class Solution {
public:
    vector<int> dfs(TreeNode*root)//返回状态、最小值、最大值、和
    {
        if(root==NULL) return {true,INT_MAX,INT_MIN,0};
        vector<int> ar=dfs(root->right);
        vector<int> al=dfs(root->left);
        if(!ar[0]||!al[0]||root->val<=al[2]||root->val>=ar[1])
        {
            return {false,0,0,0};
        }
        int sum=ar[3]+al[3]+root->val;
        int maxnn=root->right==NULL?root->val:ar[2];
        int minn=root->left==NULL?root->val:al[1];
        ans=max(ans,sum);
        return {true,minn,maxnn,sum};
    }
    int maxSumBST(TreeNode* root) {
        ans=0;//力扣上定义全局变量需要再初始化一次。
        dfs(root);
        return ans;
    }
};

另外还有一种更好的写法:
dfs的过程中,判断这个子树是否为二叉搜索树,是的话直接求这颗树的键值和,比上面的方法快。

int ans=0;
class Solution {
public:
    bool judge(TreeNode*root)
    {
        int flag1=0,flag2=0;
        if(!root->right){
            flag1=1;
        }
        else{
            flag1=(root->val<root->right->val)&&judge(root->right);
        }
        if(!root->left){
            flag2=1;
        }
        else{
            flag2=(root->val>root->left->val)&&judge(root->left);
        }
        //if(root->val==5) cout<<flag1<<" ** "<<flag2<<endl;
        //cout<<root->val<<" "<<(flag1&&flag2)<<endl;
        return flag2&&flag1;
    }
    int calculate(TreeNode*root){
        if(!root) return 0;
        int s1=calculate(root->right);
        int s2=calculate(root->left);
        ans=max(root->val+s1+s2,ans);
        return root->val+s1+s2;
    }
    void dfs(TreeNode*root){
        if(!root) return;
        if(!judge(root)){
            if(root->right) dfs(root->right);
            if(root->left) dfs(root->left);
        }
        else{
            ans=max(ans,calculate(root));
        }
    }
    int maxSumBST(TreeNode* root) {
            ans=0;
            dfs(root);
            return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值