「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
题目
链接:leetcode-cn.com/problems/va…
给你一个二叉树的根节点 root
,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
**输入:**root = [2,1,3] **输出:**true
示例 2:
**输入:**root = [5,1,4,null,null,3,6] **输出:**false **解释:**根节点的值是 5 ,但是右子节点的值是 4 。
提示:
- 树中节点数目范围在
[1, 104]
内 -231 <= Node.val <= 231 - 1
思路
递归遍历
分析
递归遍历,所有节点满足,二叉树的左孩子 < 根, 右孩子 > 根
代码
var isValidBST = function(root) {
function dfs(root){
if (root == null ){
return true
}
if (root.left){
if (root.left.val >= root.val) return false
}
if (root.right){
if (root.right.val <= root.val) return false
}
return dfs(root.left) && dfs(root.right)
}
return dfs(root)
};
但是这样也不一定正确,如下面的case就不通过
[10,5,15,null,null,6,20] 返回true,期望false
实际上BST,需要整个右子树都大于根,整个左子树都小于根
前面已经判断了,右孩子一定大于根,左孩子一定小于根;
需要再附加条件:任意节点的值必须大于其左子树的最右节点;同时小于右子树的最左节点。从根节点开始检查,一旦发现不满足则返回false。
整理代码
var isValidBST = function(root) {
function dfs(root){
if (root == null ){
return true
}
if (root.left){
if (root.left.val >= root.val) return false
let rightest = getRightest(root.left)
if (rightest && root.val <= rightest.val) return false
}
if (root.right){
if (root.right.val <= root.val) return false
let leftest = getLeftest(root.right)
if (leftest && root.val >= leftest.val) return false
}
return dfs(root.left) && dfs(root.right)
}
function getRightest(node){
while (node && node.right) node = node.right
return node
}
function getLeftest(node){
while (node && node.left) node = node.left
return node
}
return dfs(root)
};
中序遍历
var isValidBST = function(root) {
var queue = []
function dfs(root){
if (!root) return
if (root.left) dfs(root.left)
if (root) queue.push(root.val)
if (root.right) dfs(root.right)
}
dfs(root)
for (let i =0; i< queue.length-1; i++){
if (queue[i] >= queue[i+1]) return false
}
return true
};
其他思路
二叉搜索树的性质就是左子树中所有节点的值都小于(这里是<而非<=)根节点,右子树中所有节点的值都大于(同理这里是>而非>=)根节点 直接递归,验证左子树的时候,将左子树值的最小范围和最大范围作为参数传入,同理右子树也是如此 细节点:初学者做这题很容易有误区:BST 不是左小右大么,那我只要检查 root.val > root.left.val 且 root.val < root.right.val 不就行了?这样是不对的,因为 BST 左小右大的特性是指 root.val 要比左子树的所有节点都更大,要比右子树的所有节点都小,你只检查左右两个子节点当然是不够的。
// 限定以 root 为根的子树节点必须满足 max.val > root.val > min.val
var isValidBST = function (root, min = -Infinity, max = Infinity) {
// 如果是空节点
if (!root) return true;
// 当前节点的值大于最小值,小于最大值;(换句话说,当前节点的值大于左子树所有节点的值,小于右子树中所有节点的值 )
// 限定左子树的最大值是 root.val,右子树的最小值是 root.val
return (
root.val > min &&
root.val < max &&
isValidBST(root.left, min, root.val) &&
isValidBST(root.right, root.val, max)
);
};