题目地址:
https://leetcode.com/problems/largest-bst-subtree/
给定一个二叉树, 求其最大二叉搜索子树的节点个数。
思路是分治。在分治DFS返回的时候,要把当前节点为树根的子树是否是BST、有多少个节点、最大值、最小值四个信息都要返回给递归的上层。前两个信息可以捏再一起返回,例如,可以用
−
1
-1
−1代表不是BST,
0
0
0代表是空树,正整数代表节点个数。这样判断一个节点为根的子树是否是BST就可以这样判断:
1、先递归搜集左右子树的信息;
2、如果左右子树有一个不是BST,则本树也不是BST,返回
(
−
1
,
0
,
0
)
(-1,0,0)
(−1,0,0)给上层,这里一旦发现不是BST,则不用返回最大最小值了,因为用不到;
3、如果左右子树都是BST,接下来就看左右子树是否可以接到本节点上。如果左子树为空或者左子树最大值小于当前节点,并且右子树为空或者右子树最小值大于当前节点,那么左右子树都可以接到本节点上,产生一棵更大的BST,此时就可以得到本节点BST的节点个数(等于
1
1
1加上左右子树的节点个数),也可以得到本节点BST的最大和最小值,用本节点BST的节点个数更新最终答案,然后返回给上层;
4、如果两个子树有其中一棵接不上去,则说明本节点的树不是BST,返回
(
−
1
,
0
,
0
)
(-1,0,0)
(−1,0,0)给上层。
代码如下:
/**
* Definition for a binary tree node.
* 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) {}
* };
*/
class Solution {
public:
int largestBSTSubtree(TreeNode* root) {
int res = 0;
dfs(root, res);
return res;
}
struct Node {
int cnt, m, M;
};
Node dfs(auto cur, int& res) {
if (!cur) return {0, 0, 0};
auto l = dfs(cur->left, res), r = dfs(cur->right, res);
// 如果左右子树其中一个不是BST,则直接标记-1返回
if (!~l.cnt || !~r.cnt) return {-1, 0, 0};
// 如果左右子树都能接到cur上,就更新最终答案
if ((!cur->left || cur->val > l.M) && (!cur->right || cur->val < r.m)) {
res = max(res, 1 + l.cnt + r.cnt);
int m, M;
m = M = cur->val;
if (cur->left) m = l.m;
if (cur->right) M = r.M;
return {1 + l.cnt + r.cnt, m, M};
}
// 到这一步说明左右子树其中一个不能接到cur上,即cur子树不是BST,标记-1返回
return {-1, 0, 0};
}
};
时间复杂度 O ( n ) O(n) O(n),空间 O ( h ) O(h) O(h)。