1 题目
https://leetcode.cn/problems/validate-binary-search-tree/description/
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含
小于
当前节点的数。 - 节点的右子树只包含
大于
当前节点的数。 - 所有左子树和右子树自身必须也是二叉搜索树。
2 思路(错误)
根据上面的规则,递归判断
当出现不满足条件的节点,则返回false
当遍历所有的节点后,没有出现false的情况,则为true
注意:递归时的返回值
class Solution{
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
boolean result = true;
if (root.left != null) result = root.left.val < root.val;
if (root.right != null) result = root.val < root.right.val;
if (!result) return result;
result = isValidBST(root.left);
if (!result) return result;
result = isValidBST(root.right);
if (!result) return result;
return true;
}
}
BUG1
逐个比较的问题,不能比较整个子树;当右子树中出现不合法的情况查不出来
10 5 null null 15 6 null null 20
正确答案: false
程序结果: true
FIX1 中序递归
二叉搜索树的先验知识:中序遍历二叉搜索树,这个序列为递增序列
知道这点后,可以获取中序遍历的序列,检测其是否递增即可
对于上面的代码如何改进?
采用中序遍历的方式,检测元素是否递增
class Solution {
private long maxVal = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
boolean left = isValidBST(root.left);
if (!left) return false;
// 检测中序元素是否递增
if (maxVal < root.val) maxVal = root.val;
else return false;
boolean right = isValidBST(root.right);
if (!right) return false;
return true;
}
}
小问题:
样例中最小节点可能是int的最小值,会比较出错;此时可以初始化比较元素为long
的最小值。
FIX2 遍历
获取序列,检测是否递增
class Solution {
public boolean isValidBST(TreeNode root) {
List<Integer> numList = new LinkedList<>();
inorderBST(root, numList);
for (int i = 0; i < numList.size() - 1; i++) {
if (numList.get(i) >= numList.get(i+1)) return false;
}
return true;
}
private void inorderBST(TreeNode root, List<Integer> numList) {
if (root != null) {
inorderBST(root.left, numList);
numList.add(root.val);
inorderBST(root.right, numList);
}
}
}
遍历的方式最慢,因为要彻底遍历整个树;对于递归的情况,如果遇到不满足的情况就即刻返回了,不会遍历整个树;
FIX3 中序遍历中使用prev指针
class Solution {
private TreeNode prev = null;
public boolean isValidBST(TreeNode root) {
if (root != null) {
boolean leftResult = isValidBST(root.left);
if (!leftResult) return false; // 提前返回
if (prev != null) {
if (prev.val >= root.val) return false;
}
prev = root;
boolean rightResult = isValidBST(root.right);
if (!rightResult) return false;
// 全部扫描完成
return true;
}
// 空的二叉树也返回true
return true;
}
}
Note:
二叉树全局扫描还是局部扫描?
在判断BST的过程中,如果局部出现不合规的情况,就说明整体不合规,因此不需要全局扫描,所以要提前进行返回,返回false。如果全局都扫描了,没有发现不合规的情况,此时返回true;
因此判断二叉搜索树
是局部扫描和全局扫描的结合
不合规的情况提前返回
...
if (leftResult == false) return false;
...
if (rightResult == false) return false;
全部扫描完成,返回true
if (root != null) {
// left
// right
// 所有的扫描完成
return true;
}
ACM输入输出
import java.util.*;
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode() {}
public TreeNode(int val) {this.val = val; }
}
// solution
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Solution solution = new Solution();
while (in.hasNext()) {
String[] strNums = in.nextLine().split(" ");
List<TreeNode> nodes = new LinkedList<>();
for (String strNum: strNums) {
if (!strNum.isEmpty()) {
if (strNum.equals("null")) {
nodes.add(null);
} else {
nodes.add(new TreeNode(Integer.parseInt(strNum)));
}
}
}
TreeNode root = constructTree(nodes);
boolean r = solution.isValidBST(root);
System.out.println(r);
}
}
public static TreeNode constructTree(List<TreeNode> nodes) {
if (!nodes.isEmpty()) {
TreeNode node = nodes.remove(0);
if (node != null) {
node.left = constructTree(nodes);
node.right = constructTree(nodes);
}
return node;
}
return null;
}
}