题目描述
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
题目链接:
https://leetcode-cn.com/problems/validate-binary-search-tree/
错误思路
好吧,之前看覃超老师算法视频的时候,他一直强调要从子树的纬度去观察二叉搜索树,而不是子节点,当时也默默点头了。结果这道题,上来就是一把梭,还是栽在了这个错误上。
乍一看不是很简单的吗?每次拿当前节点与左右子节点作比较,递归进行,直到遍历了整棵树,中途碰到不合法的情况则终止递归。
代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
if (root.left != null) {
if (root.left.val > root.val) return false;
isValidBST(root.left);
}
if (root.right != null) {
if (root.right.val < root.val) return false;
isValidBST(root.right);
}
return true;
}
}
碰到类似下面这种情况,明明是不合规的二叉搜索树,但是程序仅仅判断 节点9 是否小于 节点11,却忽略了最小下界 10。
设置上下边界
吸取了前面的教训,我们知道在遍历二叉树时,需要告知上下边界,例如上述例子中,我们遍历到节点9 时,应该告诉它此时的上边界 upper = 11,下边界 lower = 10(父节点的上边界),检测发现 9 < lower,故得知这是一棵不合规的二叉搜索树。
代码如下:
public boolean isValidBST(TreeNode root) {
return helper(root, null, null);
}
public boolean helper(TreeNode root, Integer lower, Integer upper) {
if (root == null) return true;
if (lower != null && root.val <= lower) return false;
if (upper != null && root.val >= upper) return false;
// 遍历左节点时不断更新上界
if (!helper(root.left, lower, root.val)) return false;
// 遍历右节点时不断更新下界
if (!helper(root.right, root.val, upper)) return false;
return true;
}
中序遍历
这边还可以利用二叉搜索树的特性,它的中序遍历元素是递增的。因此只需要中序遍历二叉搜索树,然后检查遍历结果是否为递增。
代码如下:
Integer max = null;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
if (!isValidBST(root.left)) return false;
// 更新当前最大值
if (max != null && root.val <= max) return false;
max = root.val;
if (!isValidBST(root.right)) return false;
return true;
}
总结
递归确实比较难理解,但是如果通过长时间的练习,也能让你形成递归思路。
这边分享一下覃超老师的递归代码 template,写递归时需要先把这些部分搞清楚。
public void recursion(int level, int param) {
// terminator 递归出口
if (level == 100) return;
// process 处理逻辑
param = 1;
// drill down 向下递归
recursion(level + 1, param);
// reverse states 必要时候,需要清理当前层的状态
param = 0;
}
熟练之后,相信你也能做到递归一把梭。如果觉得文章对你有帮助,欢迎留言点赞。