文章目录
碎碎念
好!好久没刷leetcode了,欠了好多个题解没给自己补上我有罪...以至于现在好多都忘记了当时怎么做的以及有啥问题...我接下来一定及时写啊啊啊啊!
好累好累啊啊啊最近!忙完你的忙你的忙完你的忙你的...看的眼睛酸酸累累的。不管了,既然这篇开坑了就写完它!
一、题目


二、思路和题解
1.思路
难死我了呃呃呃呃呃
做二叉树相关的题目第一反应还是递归了,但由于苯人对二叉搜索树(BST,Binary Search Tree)的概念还是把握的不是很清晰啊于是只考虑一层的:左节点值小于根节点值,右节点值大于根节点值。一旦出现错的就返回false,没有就继续递归左子树和右子树,直到找到最后都没有false就可以返回true了。
但是!!二叉搜索树不是这样的!二叉搜索树要求左子树的所有节点的值都要小于根节点的值,右子树的所有节点的值也要大于根节点的值。所!以!咱们需要用新的min_node和max_node变量来存储当前的上界和下界(所以就要引入辅助函数啦),也就是这个节点在什么样一个范围里才是合法的,如果不在这个范围,那就直接false。
举个合法的二叉搜索树的例子,这里我按照层序来一个个讲:
text
5 (根节点)
/ \
3 7 (3是左子树,7是右子树)
/ \ / \
2 4 6 8 (叶子节点)
- 最开始的时候根节点的取值是没有限制的,因此它没有上界和下界;
- 到3这个节点时,按BST的规则,这个节点必须小于父节点的值,所以上界是5,下界依旧没有;
- 到7这个节点时,按BST的规则,这个节点必须大于父节点的值,所以下界是5,上界依旧没有;
- 再往下,到2这个节点时,上界是3,下界没有;
- 到4这个节点就要注意了,它在3的右子树,所以下界是3,但它同时也在5的左子树,所以上界是5;
- 到6节点,一样的,它在7的左子树,所以上界是7,同时它也在5的右子树,所以下界是5;
- 8这个节点在7的右子树,也在5的右子树,所以下界是5和7,取大的,下界是7。
很显然的,每个节点的值都是在合法的范围的,因此这就是一个合法的BST。
这里的上下界我们手工是看的明白的,但在代码里,就需要"继承"一下啦,我们直接看代码!(建议跟着代码走一遍~)
2.代码(递归)
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:
// 辅助函数,可以"继承"上下界的值,也可以判断是否在范围内
bool checkBST(TreeNode* root, TreeNode* min_node, TreeNode* max_node){
// 边界条件
if (root==nullptr){
return true;
}
// 如果超出下界,不合法
if (min_node!=nullptr&&root->val<=min_node->val){
return false;
}
// 如果超出上界,不合法
if (max_node!=nullptr&&root->val>=max_node->val){
return false;
}
// 需要接收递归传回来的值,然后查看左右子树是否都合法
// 注意这里左节点的下界是继承的,上界更新;右节点的上界是继承的,下界更新
return
checkBST(root->left,min_node,root)&&checkBST(root->right,root,max_node);
}
bool isValidBST(TreeNode* root) {
// 初始状态上界和下界都是null
return checkBST(root,nullptr,nullptr);
}
};
三、其他解法(中序遍历+判断升序)
1.思路
BST的特点是中序遍历的话是升序的!!
利用这个特点就可以美美解决了,只要不是升序的就是false。
中序遍历请看:【leetcode】94.二叉树的中序遍历(含前序、后序遍历相关内容)
这里我就用的栈模拟了。
2.代码
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:
// 中序遍历+升序判断
bool isValidBST(TreeNode* root) {
vector<int> res; // 存储遍历结果
stack<TreeNode*> st; // 辅助栈
TreeNode* cur = root; // 游标指针,从根节点开始
// 循环条件:cur非空或栈非空(两者都空说明遍历完成)
while (cur != nullptr || !st.empty()) {
// 把当前节点的所有左孩子依次入栈
if (cur != nullptr) {
st.push(cur);
cur = cur->left;
} else {
// 栈顶出栈,访问根节点(加入结果)
cur = st.top();
st.pop();
res.push_back(cur->val);
// 处理右子树,游标指向右孩子
cur = cur->right;
}
}
//判断是否升序
for (int i = 0; i < res.size() - 1; i++) {
if (res[i] >= res[i + 1]) {
return false;
}
}
return true;
}
};
四、错误回顾
1.对BST概念和特点不熟悉,思路上有漏洞,只考虑了一层
2.树的一些基本语法也是手太生了哈,居然都写成root->left.val了...(正确是root->left->val!!!)