二叉树_题目21:1373. 二叉搜索子树的最大键值和

78 阅读4分钟

题目21:1373. 二叉搜索子树的最大键值和

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

提示:

  • 每棵树有 140000 个节点。
  • 每个节点的键值在 [-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…