【算法20天:Day20】第六章二叉树 LeetCode 验证二叉搜索树(98)

64 阅读2分钟

题目四:

image.png

解法一:(辅助数组)

解题思路:

要知道中序遍历下,输出的二叉搜索树节点的数值是有序序列。

有了这个特性,验证二叉搜索树,就相当于变成了判断一个序列是不是递增的了。

可以递归中序遍历将二叉搜索树转变成一个数组:

var preOrder = function(root) {
    if(root === null) {
        return
    }
    preOrder(root.left)
    preOrderArr.push(root.val)
    preOrder(root.right)
}

然后只要比较一下,这个数组是否是有序的,注意二叉搜索树中不能有重复元素

preOrder(root)
for (let i = 1; i < preOrderArr.length; i++) {
    if (preOrderArr[i] <= preOrderArr[i - 1]) {
        return false
    }
}
return true

整体代码:

var isValidBST = function(root) {
    const preOrderArr = []
    var preOrder = function(root) {
        if(root === null) {
            return
        }
        preOrder(root.left)
        preOrderArr.push(root.val)
        preOrder(root.right)
    }
    preOrder(root)
    for (let i = 1; i < preOrderArr.length; i++) {
        if (preOrderArr[i] <= preOrderArr[i - 1]) {
            return false
        }
    }
    return true
};

注意:这个题有个容易陷入的陷阱。

陷阱:不能单纯的比较左节点小于中间节点,右节点大于中间节点就完事了

写出了类似这样的代码:

if (root.val > root.left.val && root.val < root.right.val) {
    return true;
} else {
    return false;
}

我们要比较的是 左子树所有节点小于中间节点,右子树所有节点大于中间节点。所以以上代码的判断逻辑是错误的。

例如: [10,5,15,null,null,6,20] 这个case:

image.png

节点10大于左节点5,小于右节点15,但右子树里出现了一个6 这就不符合了!

解法二:(递归)

这个解法还没理解到。

let pre = null;
var isValidBST = function (root) {
    let pre = null;
    const inOrder = (root) => {
        if (root === null)
            return true;
        let left = inOrder(root.left);

        if (pre !== null && pre.val >= root.val)
            return false;
        pre = root;

        let right = inOrder(root.right);
        return left && right;
    }
    return inOrder(root);
};

解法三:(参考Leetcode官方)

解题思路:

要解决这道题首先我们要了解二叉搜索树有什么性质可以给我们利用,由题目给出的信息我们可以知道:如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;它的左右子树也为二叉搜索树。

这启示我们设计一个递归函数 helper(root, lower, upper) 来递归判断,函数表示考虑以 root 为根的子树,判断子树中所有节点的值是否都在 (l,r)(l,r) 的范围内(注意是开区间)。如果 root 节点的值 val 不在 (l,r)(l,r) 的范围内说明不满足条件直接返回,否则我们要继续递归调用检查它的左右子树是否满足,如果都满足才说明这是一棵二叉搜索树。

那么根据二叉搜索树的性质,在递归调用左子树时,我们需要把上界 upper 改为 root.val,即调用 helper(root.left, lower, root.val),因为左子树里所有节点的值均小于它的根节点的值。同理递归调用右子树时,我们需要把下界 lower 改为 root.val,即调用 helper(root.right, root.val, upper)。

函数递归调用的入口为 helper(root, -inf, +inf), inf 表示一个无穷大的值。

const helper = (root, lower, upper) => {
    if (root === null) {
        return true;
    }
    if (root.val <= lower || root.val >= upper) {//终止条件 不满足二叉搜索树的性质
        return false;
    }
  	//递归左右子树
    return helper(root.left, lower, root.val) && helper(root.right, root.val, upper);
}
var isValidBST = function(root) {
  	//定义low=-Infinity,让所有值都大于low
  	//定义upper=Infinity,让所有值都小于upper
    return helper(root, -Infinity, Infinity);
};