题目描述
想法 1
采用递归的方式,判断左节点小于根,右节点大于根。
结果:错误。
错误案例为:
原因:右孩子的左孩子(右孙子)可能小于父亲。 6 < 10,出错。
想到的解决方案:在递归过程中吧祖先记录下来,用以后续的比较。
想法 2
在递归过程中加入祖先,并且加入 bool 标识指示是左孩子还是右孩子。
public class Solution1 {
public boolean isValidBST(TreeNode root) {
return isValid(root, new ArrayList<>(), false);
}
public boolean isValid(TreeNode root, ArrayList<TreeNode> parents, boolean isRight) {
if (root == null) return true;
boolean left = root.left == null;
boolean right = root.right == null;
if (root.left != null && root.left.val >= root.val) return false;
if (root.right != null && root.right.val <= root.val) return false;
for (TreeNode parent : parents) {
if (isRight && root.left != null && root.left.val <= parent.val) return false;
if (!isRight && root.right != null && root.right.val >= parent.val) return false;
}
ArrayList<TreeNode> clone = (ArrayList<TreeNode>)parents.clone();
clone.add(root);
left = isValid(root.left, clone, false);
right = isValid(root.right, clone, true);
return left && right;
}
}
再次出错,出错案例为:
出错原因:曾孙子,曾曾孙子都有可能出错。上述为 根为 1 的左右标记覆盖了根为 3 的左右标记,导致 最下面的 3 无法被判误。
解决方法:标记去除,换为上下界,每次迭代按收窄趋势更新上下界。因此有了想法 3。
想法 3
public class Solution1 {
public boolean isValidBST(TreeNode root) {
return isValid(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public boolean isValid(TreeNode root, int min, int max) {
if (root == null) return true;
if (root.val <= min || root.val >= max) return false;
boolean left = isValid(root.left, min, root.val);
boolean right = isValid(root.right, root.val, max);
return left && right;
}
}
代码大大减少,并且能够覆盖上述的情况。
但出现了边界问题,当节点的值为 MIN
或者 MAX
时,会直接判断错误。
但是,存在一些 MIN
,MAX
为正确的案例。
无法解决。。。
看答案。。。
查阅答案后发现,把边界的类型改为 Long
即可
public class Solution1 {
public boolean isValidBST(TreeNode root) {
return isValid(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean isValid(TreeNode root, Long min, Long max) {
if (root == null) return true;
if (root.val <= min || root.val >= max) return false;
boolean left = isValid(root.left, min, (long) root.val);
boolean right = isValid(root.right, (long) root.val, max);
return left && right;
}
}
在答案中还看到了另外一种思路:
原文
采用中序遍历二叉树,获得的值按升序,即表示为合格的 BST。
public class Solution2 {
long pre = Long.MIN_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
// 访问左子树
if (!isValidBST(root.left)) {
return false;
}
// 访问当前节点:如果当前节点小于等于中序遍历的前一个节点,说明不满足BST,返回 false;否则继续遍历。
if (root.val <= pre) {
return false;
}
pre = root.val;
// 访问右子树
return isValidBST(root.right);
}
}
与上述方法相同的思路,有以下的写法:
public class Solution3 {
double last = -Double.MAX_VALUE;
public boolean isValidBST(TreeNode root) {
if (root == null) {
return true;
}
if (isValidBST(root.left)) {
if (last < root.val) {
last = root.val;
return isValidBST(root.right);
}
}
return false;
}
}
推荐采用第一种,原因是:
对于一个 BST 的否定,是分离的 false statement。但对于它的肯定,则需要串联的 true statement。
因此进行否定的难度较小。