Leetcode 98: 验证二叉树

题目描述

题目

想法 1

采用递归的方式,判断左节点小于根,右节点大于根。
结果:错误。
错误案例为:
图 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。
因此进行否定的难度较小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值