JS 数据结构和算法 验证二叉搜索树

385 阅读2分钟

题号:98

题目解读:

  1. 判断一棵二叉树是不是二叉搜索树。二叉搜索树需要满足:所有左子树上的节点的值小于当前节点的值,所有右子树上的节点的值小于当前节点的值。
  2. 陷阱1:只比较当前节点,和左右子节点的值 没有考虑整棵子树

1. 递归

时间:O(n) n是节点的个数

空间:O(n) n是栈空间的利用

核心思路是:

  1. 采用递归,退出条件 节点为null就返回true
  2. 每一层递归,当前节点的值要处于一个范围区间。如果是左节点,那么当前的root.val所处的区间是(-infinity, 当前节点的值),如果是右节点,(root.val, infinity)。注意是开区间,题目描述是“大于”“小于”


// 递归函数
const helper = (root, lower, upper) => {
    // 1. 【递归的退出条件】当前节点是null 就返回true 为什么?因为叶子节点的话,可以不用比
    if (root === null) {
        return true
    }
    // 2. 【单层递归逻辑】如果越界 就return false
    if (root.val < lower || root.val > upper) {
        return false
    }
    // 3. 【递归点 传入参数 左右节点】
    //    左节点递归【lower是 -Infinity upper是“当前节点” 因为后面的值都要比当前的值小 所以设置upper】
    //    右节点递归【upper是 Infinity lower是当前节点 因为后的值都要比当前值大 所以设置lower】
    return helper(root.left, -Infinity, root.val) && helper(root.right, root.val, Infinity)
}

// 主函数
var isValidBST = function (root) {
    return helper(root, -Infinity, Infinity)
};

测试数据

function Node(val) {
    this.val = val;
    this.left = null;
    this.right = null;
}
var a = new Node(6)
var b = new Node(4)
var c = new Node(8)
// var d = new Node(3)
// var e = new Node(4)
var f = new Node(7)
var g = new Node(2)
a.left = b
a.right = c
c.left = f
c.right = g
console.log(isValidBST(a));

2. 迭代

时间:O(n)

空间:O(n)

核心思路:1. 利用中序遍历的顺序,左中右 + 二叉搜索树的顺序 左小右大, 不断记录上一个节点的值,和当前节点进行比较。只要当前节点值小于上一个节点,就return false

var isValidBST = function (root) {
    // 1. 初始化变量
    // 栈数组
    const stack = []
    // 游标 current
    let current = root
    // 记录前一个节点
    let pre = null
    while (stack.length > 0 || current !== null) {
        // 1. 中序遍历的套路 不断遍历 把游标的节点加入栈
        if (current) {
            stack.push(current)
            // 2. 不断遍历左子树 节点 加入栈
            current = current.left
        } else {
            // 3. 如果碰到了叶子节点 就取出栈的元素 判断值是否小于上一个节点的值
            current = stack.pop()
            // 4. 如果小于 证明不是二叉搜索树 因为二叉搜索树 左 - 中 - 右 应该是递增的顺序
            if (pre !== null && current.val <= pre.val) {
                return false
            }
            // 5. 修改上一个节点的值 为当前的节点
            pre = current
            // 6. 中序遍历的套路 修改游标
            current = current.right
        }
    }
};

测试数据

function Node(val) {
    this.val = val;
    this.left = null;
    this.right = null;
}
var a = new Node(6)
var b = new Node(4)
var c = new Node(8)
// var d = new Node(3)
// var e = new Node(4)
var f = new Node(7)
var g = new Node(2)
a.left = b
a.right = c
// b.left = d
// b.right = e
c.left = f
c.right = g
console.log(isValidBST(a));