cpp
/**
* 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:
vector<int>nums;
vector<int> inorder(TreeNode *root){
if(root == nullptr){
return nums;
}
inorder(root->left);
nums.push_back(root->val);
inorder(root->right);
return nums;
}
bool isValidBST(TreeNode* root) {
vector<int>res;
res = inorder(root);
for(int i = 1;i<res.size();i++){
if(res[i]<=res[i-1]){
return false;
}
}
return true;
}
};
cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* };
*/
class Solution {
public:
// helper函数作用:
// 判断以root为根节点的树是否满足BST条件
//
// lower:当前节点允许的最小值
// upper:当前节点允许的最大值
//
// 当前节点必须满足:
// lower < root->val < upper
bool helper(TreeNode* root, long long lower, long long upper) {
// 1. 递归终止条件
//
// 空节点不违反BST规则
// 所以返回true
if(root == nullptr){
return true;
}
// 2. 判断当前节点是否合法
//
// BST要求:
// 当前节点必须严格大于lower
// 且严格小于upper
//
// 如果超出范围,说明不是BST
if(root->val <= lower || root->val >= upper){
return false;
}
// 3. 递归检查左子树
//
// 左子树所有节点都必须小于当前节点
//
// 所以:
// 上界变成当前节点值
//
// 原范围:
// (lower, upper)
//
// 左子树范围:
// (lower, root->val)
bool left = helper(root->left, lower, root->val);
// 4. 递归检查右子树
//
// 右子树所有节点都必须大于当前节点
//
// 所以:
// 下界变成当前节点值
//
// 右子树范围:
// (root->val, upper)
bool right = helper(root->right, root->val, upper);
// 5. 左右子树都满足BST条件
// 当前树才是BST
return left && right;
}
bool isValidBST(TreeNode* root) {
// 根节点一开始没有限制
// 所以给一个最大范围
return helper(root, LONG_MIN, LONG_MAX);
}
};
递归思路总结
这道题的核心不是比较:
root->left < root
root->right > root
因为这样只能判断直接孩子。
例如:
5
/ \
3 8
/
4
看起来:
4 < 8
好像满足。
但是 4 在 5 的右子树中。
BST要求:
右子树所有节点 > 5
而:
4 < 5
所以错误。
上下界递归的核心
进入每一层递归,都给当前节点一个合法范围。
比如:
8
/ \
3 10
/
1
开始:
8的范围:
(-∞, +∞)
检查左孩子3:
因为3在8左边:
3必须满足:
-∞ < 3 < 8
所以递归:
helper(3, LONG_MIN, 8)
检查1:
因为1在3左边:
范围继续缩小:
-∞ < 1 < 3
所以:
helper(1, LONG_MIN, 3)
你会发现:
递归过程中,范围越来越严格。
递归模板
以后遇到类似树的递归,可以套:
返回值 dfs(节点, 当前限制){
// 1. 终止条件
if(节点为空){
return 初始结果;
}
// 2. 当前节点处理
// 3. 递归处理子树
// 4. 合并子树结果
return 结果;
}
这题:
dfs(root, lower, upper)
代表:
判断当前节点是否在合法范围内,并继续检查左右子树。
这道题记忆重点
记住三句话:
① BST性质
左子树所有节点 < 根节点 < 右子树所有节点
② 递归传递范围
左子树:
helper(root->left, lower, root->val)
因为:
左边最大不能超过当前节点
右子树:
helper(root->right, root->val, upper)
因为:
右边最小不能低于当前节点
③ 递归思想
不要想着:
我要把整棵树全部检查完。
而是:
我相信 helper 可以检查好左右子树,我只需要检查当前节点,并把正确范围传下去。
这就是递归在二叉树问题中的核心思想。