一、前言
描述
给定一个二叉树,判断它是否是合法的二叉查找树(BST)
一棵BST定义为:
节点的左子树中的值要严格小于该节点的值。
节点的右子树中的值要严格大于该节点的值。
左右子树也必须是二叉查找树。
一个节点的树也是二叉查找树。
二、算法思路
错误想法:只考虑当前结点及左右子结点
public class Solution {
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
public boolean isValidBST(TreeNode root) {
// write your code here
if(root == null){
return true;
}
//只考虑当前结点及左右孩子结点满足
// left.val < root.val < right.val
if(root.left != null && root.left.val >= root.val
|| root.right !=null && root.right.val <= root.val){
return false;
}
if(!isValidBST(root.left))return false;
if(!isValidBST(root.right))return false;
return true;
}
}
反例:
方法一:按照BST定义递归二叉树,左子树的所有结点必须小于当前结点,且右子树的所有结点必须大于当前结点,同时,顺着某个结点的左孩子一直往右走的结点都必须小于该结点,而顺着某个结点的右孩子一直往左走的结点都必须大于该结点,重复此过程即可求解。
方法二:使用中序遍历,若是BST,则遍历顺序是递增的,因此定义两个全局变量last和flag分别记录上一个访问的结点值和是否有结点小于等于last的,若有则退出递归
三、算法Java实现
方法一:前序遍历
public class Solution {
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
public boolean isValidBST(TreeNode root) {
// write your code here
return isValidBST(root, null, null);
}
private boolean isValidBST(TreeNode root, Integer low, Integer high){
if(root == null){
return true;
}
//不在上下界范围内,不是BST
if(low != null && root.val <= low
|| high!= null && root.val >= high) return false;
//若low != null,则说明root.left这个结点的父结点root是某个结点的右孩子,
//即要满足顺着某个结点的右孩子一直往左走的结点都必须大于该结点,
//而low就是该结点的值(因为只有往右走才会更新low),所以下界是low,
//而当前结点的左子树所有结点又都必须小于当前结点的值,固上界是root.val
if(root.left != null
&& !isValidBST(root.left, low, root.val))return false;
if(root.right != null
&& !isValidBST(root.right, root.val, high))return false;
return true;
}
}
图1
图2
从图1可以看出所有左子树下的右子树的根结点要求其小于爷爷结点,
从图2可以看出所有右子树下的左子树的根结点要求其大于爷爷结点
方法二:中序遍历
public class Solution {
//此处一定要是long类型
//若是int类型,则当测试数据为一个int的最小负数时,
//last == root.val, flag被置为false,而一个结点是BST,答案就错了
private long last = Long.MIN_VALUE;
private boolean flag = true;
/**
* @param root: The root of binary tree.
* @return: True if the binary tree is BST, or false
*/
public boolean isValidBST(TreeNode root) {
// write your code here
return isValidBST2(root);
}
private boolean isValidBST2(TreeNode root){
//这里条件不能写成root == null || root.left == null && root.right == null
//因为当走到最左的结点即遍历的第一个结点时,还没记录下这个结点就返回到上一层了
if(root == null){
return true;
}
if(root.left != null && flag) isValidBST2(root.left);
if(root != null && root.val <= last){
flag = false;
}
last = new Long(root.val);
//有一个不满足条件就退出循环
if(!flag){
return false;
}
if(root.right != null && flag) isValidBST2(root.right);
//遍历完左右子树及当前结点则返回继续遍历其父节点
return flag;
}
}