问题描述
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例
输入:
2
/ \
1 3
输出: true
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
思路
这题一开始想用优雅的递归来做。但是我搞不懂怎么返回左子树最大的值和右子树最小的值。(java不好实现,Python可以实现) 如果左子树最大的值都比根结点的值小,同理,右子树最小的值都比根结点元素大,那么肯定符合题意。
那么,另辟蹊径。 用层序遍历来做(其实什么遍历都可以,重点是不用递归实现的还是层序遍历方便)。然后判定左子树的元素是否都小于根结点的值。右子树是否都大于。 把所有的结点都判定一遍,就得到答案了。(方法一)
贼心不死,想了想既然不能由下往上返回值,那么能不能由上到下传参的方式来解决这个问题呢? 当然可以!每棵子树中的值都被限定了一定的范围。不失一般性,我们考虑很大的一棵树。 我们讨论的结点是某棵树的左子树的右子树的根结点。
那么,这棵右子树的根结点的值的上限由整棵树的树根决定,下限由它自己的根决定。 所以我们要往下传递两个参数,一个是当前结点的上限,一个是当前结点的下限。 那么,没有上下限时怎么办?好办,Java有包装类,用包装类传递,这样就能传null了。没有上下线就传null呗。(方法二)
还有,不要忘记二叉搜索树(二叉排序树)的一个重要性质:中序遍历这棵树得到一个有序序列。 所以我们设置一个last值记录中序遍历的上一个值。判断即可。(方法三)
方法一
public boolean isValidBST1(TreeNode root) {
if(root == null) return true;
boolean childFlag = isValidBST1(root.left)&&isValidBST1(root.right);
if(!childFlag) return false;
ArrayList<Integer> left = getAllVal(root.left);
ArrayList<Integer> right = getAllVal(root.right);
for(int l:left) if(l >= root.val) return false;
for(int r:right) if(r <= root.val) return false;
return true;
}
private ArrayList<Integer> getAllVal(TreeNode root){
if(root == null) return new ArrayList<>();
ArrayList<Integer> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(queue.size() > 0){
TreeNode curNode = queue.poll();
res.add(curNode.val);
if(curNode.left != null) queue.add(curNode.left);
if(curNode.right != null) queue.add(curNode.right);
}
return res;
}
方法二
java版
public boolean isValidBST(TreeNode root){
if(root == null) return true;
return next(root,null,null);
}
private boolean next(TreeNode root, Integer max, Integer min){
if(root == null) return true;
int val = root.val;
if(min != null && val <= min) return false;
if(max != null && val >= max) return false;
if(!next(root.left,val,min)) return false;
return next(root.right, max, val);
}
Python版
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
return self.isValid(root, None, None)
def isValid(self, root, maxs, mins):
if not root:
return True
if maxs is not None and root.val >= maxs:
return False
if mins is not None and root.val <= mins:
return False
return self.isValid(root.left,root.val,mins) and self.isValid(root.right,maxs,root.val)
方法三
class Solution {
Integer last;
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
if(!isValidBST(root.left)) return false;
if(last != null && last >= root.val) return false;
last = root.val;
return isValidBST(root.right);
}
}