给你一个二叉树的根节点
root
,判断其是否是一个有效的二叉搜索树。
解法1 递归
思路
验证二叉搜索树,可以参考验证对称二叉树的思想递归的去分解子问题。首先左子树的是二叉搜索树并且左子树的所有节点小于根节点,右子树也是二叉搜索树并且右子树的所有节点都大于根节点。
最开始的时候我写出了这样的代码:
js
function isValidBST(root: TreeNode | null): boolean {
if (!root) return true;
if (root.left?.val && root.left.val >= root.val) {
return false; // 只比较了左节点和根节点的值大小
}
if (root.right?.val && root.right.val <= root.val) {
return false; // 只比较了右节点和根节点的值大小
}
const isValidLeft = isValidBST(root.left);
const isValidRight = isValidBST(root.right);
return isValidLeft && isValidRight;
};
这样的代码的问题在于,只比较了左右节点和根节点的值大小 ,而不是所有左右子树的节点大小,所以我们需要一个额外区间参数来规定该节点的值,如果超出了,那就不是二叉搜索树。所以我们需要一个辅助函数来去规定根节点值的 lower
和 upper
。然后再递归时更新左右子树的lower
和 upper
。
代码
js
function isValidBST(root: TreeNode | null): boolean {
const helper = (node, lower, upper) => {
if (!node) return true;
if (node.val <= lower || node.val >= upper) return false;
return helper(node.left, lower, node.val) && helper(node.right, node.val, upper);
}
return helper(root, -Infinity, Infinity);
};
时空复杂度
时间复杂度:O(n)
空间复杂度:O(logn)
解法2 中序遍历法
思路
既然是一个二叉搜索树,那它的中序遍历一定是严格递增的,不可能存在当前节点比前一个节点小的情况。
所以根据这个特性,用一个变量 prev
来保存上一个节点的值,先处理左子树,然后比较节点,比较完之后处理右子树。
代码
js
function isValidBST(root: TreeNode | null): boolean {
let prev: number | null = null; // 记录上一个节点的值
function inorder(node: TreeNode | null): boolean {
if (!node) return true; // 走到空节点说明到头了
// 1. 先遍历左子树
if (!inorder(node.left)) return false;
// 2. 然后处理当前节点
if (prev !== null && node.val <= prev) {
return false; // 中序遍历要求严格递增
}
prev = node.val; // 更新 prev
// 3. 最后遍历右子树
return inorder(node.right);
}
return inorder(root);
}
时空复杂度
时间复杂度:O(n)
空间复杂度:O(logn)