学习纪录:力扣98验证二叉搜索树(递归+迭代)
题解很简单,但是看不太懂加上又有点思路不想轻易放弃啊喂!花了几天终于搞定
收益也很大,体会到模块化编程的感觉。把功能分成两个,然后一个一个实现
题目
例子
上代码
通过isValidBST自身递归实现功能
递归
- 明确递归用得函数,是自身就可以还是需要新建一个函数。这里是自身
isValidBST
- 确定这个函数的入参应该是什么,功能是什么。 用得是自身作为递归函数,所以入参就是
root
,这个函数的功能是判断以输入的root
作为根节点的二叉树是否是二叉搜索树。 - 套路:递归函数递归自身,而二叉树中递归通常是把自己的左右节点作为入参递归调用自身。如下面的
isValidBST(root.left)和isValidBST(root.right)
。 然后既然用了这个套路,也就是上面的两个函数,isValidBST(root.left)和isValidBST(root.right)
,对于root
来说,root.left和root.right
都作为入参穿进去了。判断了root
的左子树是否是二叉搜索树,右子树是不是二叉搜索树。 return
,确定return
什么。而return
什么语句呢,可以从isValidBST(root.left)和isValidBST(root.right)
知道。isValidBST(root.right)
返回的是boolen
为root.right
是不是二叉搜索树。 而return isValidBST(root.left)&&isValidBST(root.right)
。是很容易想到的,因为大多数的规律就是return
后面跟的是调用递归函数。- 看看上面
return
之后是否可以满足题意,不满足。因为即使左子树和右子树都是二叉搜索树,也不一定是二叉搜索树。比如根节点是5,而左子树所有的节点都是大于5的,比如这个左子树[10 5 9 3 6 null null]
除了3和5都是大于5的。但是ta是二叉搜索树,对于根节点5就不是了。 - 如果5成立,即现在的代码还不够完成功能,那就加功能。从上面知道,之所以不可以,是因为一个根节点的左右子树即使都是二叉搜索树也不会使根节点那棵树成为二叉搜索树。所以如何才能让根节点那棵树成为二叉搜索树呢。 只要让左子树节点所有值小于根节点值,右子树节点所有值大于根节点的值就可以了。如果这个条件达成,那么根节点是5,而左子树所有的节点都是小于5的,同时左子树还要是二叉搜索树,那么无论怎么搞,最后都不会不是二叉搜索树,换句话来说,就是要让左子树都小于根节点,右子树都大于根节点,并且左子树和右子树都是二叉搜索树那么根节点所在的树必为二叉搜索树。
- 递归经典的需要设置返回条件,只要判断
root==null
即可。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
if(root==null){
return true;
}
if(isAllSmall(root.left,root.val)&&isAllBig(root.right,root.val)){
return isValidBST(root.left)&&isValidBST(root.right);
}else{
return false;
}
//下面的几行代码是将上面的if else判断简化
// return isAllSmall(root.left,root.val)&&isAllBig(root.right,root.val)?isValidBST(root.left)&&isValidBST(root.right):false;
//下面的几行代码是将上面的更简化
// return isAllSmall(root.left,root.val)&&isAllBig(root.right,root.val)&&isValidBST(root.left)&&isValidBST(root.right)?true:false;
}
//函数的作用:判断以root为根节点的二叉树的所有值是不是都小于val
//如果所有节点都小于val,返回true。
//如果在遍历中发现有节点值大于val,返回false。
//注意:这里面是通过广度优先算法遍历二叉树的经典算法。不再赘述
//力扣数据结构专题中涉及二叉树的遍历基本都有深度和广度优先两种算法。
public boolean isAllSmall(TreeNode root,int val){
if(root==null){
return true;
}
Deque<TreeNode> queue=new ArrayDeque<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode tmp=queue.poll();
if(tmp.val>=val){
return false;
}
if(tmp.left!=null){
queue.offer(tmp.left);
}
if(tmp.right!=null){
queue.offer(tmp.right);
}
}
return true;
}
//函数的作用:判断以root为根节点的二叉树的所有值是不是都大于val
//如果所有节点都大于val,返回true。
//如果在遍历中发现有节点值小于val,返回false。
//注意:这里面是通过广度优先算法遍历二叉树的经典算法。不再赘述
//力扣数据结构专题中涉及二叉树的遍历基本都有深度和广度优先两种算法。
public boolean isAllBig(TreeNode root,int val){
if(root==null){
return true;
}
Deque<TreeNode> queue=new ArrayDeque<>();
queue.offer(root);
while(!queue.isEmpty()){
TreeNode tmp=queue.poll();
if(tmp.val<=val){
return false;
}
if(tmp.left!=null){
queue.offer(tmp.left);
}
if(tmp.right!=null){
queue.offer(tmp.right);
}
}
return true;
}
}