题目:
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
解法1 递归方式
递归方式的话,如果按照我们一惯思想,会认为只要判断左子树小于父节点,右子树大于父节点即可,但实际并不是这样的,可能出现这样一种情况,下图,你用这样的思路去解,那么还是对的,但实际情况并非如此,如图所示,下面的就不符合二叉搜索树了。
所以我们需要再每次递归的时候,要传入两个参数,最大值和最小值,最大值则主要相对于左子树来说,他的所有元素,必须比这个最大值小,而最小值,则相对于右子树来说,他的所有元素要比这个最小值来的大
只有这样才满足条件
那么递归的话,又到了递归的三个条件
1 递归的出口
2 递归函数的作用
3 返回值
递归出口:,则是没有节点的时候,则返回true
递归函数作用: 也就是根据我们传入的最大值和最小值,分别去判断该树下的左右子树是否满足条件
返回值: 满足条件返回true,不满足返回false
代码如下:
/**
* 判断是否是二叉搜索树
* 思路: 递归的方式: 设置下限值和上限值
* 每次判断是如果左子树的的值大于节点值,则返回false
* 如果右子树的值小于上限值,则返回flase
* @param root
* @return
*/
public static boolean isValidBST(TreeNode root) {
return helpValidBST(root,null,null);
}
public static boolean helpValidBST(TreeNode root, Integer min, Integer max) {
// 1. 递归出口
if (root == null) {
return true;
}
int val = root.val;
// 2. 如果值小于最小值,不符合,相对于右子树进入递归
if(min!=null && val <= min){
return false;
}
// 值大于最大值,则表示不对,相对于左子树进入递归
if(max != null && val >= max) {
return false;
}
// 3. 递归,对于左子树,则不能大于最大值
if(!helpValidBST(root.left,min,val))return false;
// 对于右子树,则不能小于最小值
if(!helpValidBST(root.right,val,max)) return false;
return true;
}
解法2 中序遍历的方式
中序遍历: 先访问左节点,再访问根节点,再访问右节点。
使用中序遍历方式,这里的解法有两种,一种是你可以先中序遍历出来,再来判断是否该数组是有序的,如果有序,则表示是二叉搜索树。
另外一种解法,则是你在遍历的时候,当遍历到下一个节点的时候,判断是否比上一个节点大,如果不是的话,则不满足条件,直接退出。不需要遍历完。
代码如下:
/**
* 使用中序遍历方式实现
* @param root
* @return
*/
public static boolean isValidBST1(TreeNode root) {
Stack<TreeNode> stack = new Stack();
int inorder = -1;
while (!stack.isEmpty() || root != null) {
// 1. 将左子树压入栈中
while (root != null) {
stack.push(root);
root = root.left;
}
// 2. 出栈
root = stack.pop();
// 如果该值比上一个值小,则不符合条件
if (root.val <= inorder) return false;
// inorder是保存值,即遍历的的值,用来与下一个值进行比较
inorder = root.val;
// 找右子树
root = root.right;
}
return true;
}