题目
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。
思路
实现该算法的关键在于如何判断一棵二叉树是否是二叉搜索树。可以通过中序遍历的方式遍历整棵二叉树,并将遍历到的节点的值保存到一个数组中,然后判断该数组是否是升序排列的即可。
下面是 Typescript 的代码实现:
function isValidBST(root: TreeNode | null): boolean {
let prev = -Infinity
let isValid = true
function inorder(node: TreeNode | null) {
if (!node) {
return
}
inorder(node.left)
// 不满足从小到大的顺序
if (node.val <= prev) {
isValid = false
return
}
prev = node.val
inorder(node.right)
}
inorder(root)
return isValid
}
首先,我们定义一个变量 prev,用于保存上一个遍历到的节点的值。初始值为负无穷大,因为二叉搜索树中的所有节点都应该大于负无穷大。
然后,我们定义一个变量 isValid,用于判断当前二叉树是否是二叉搜索树。初始值为 true。
接下来,我们定义一个名为 inorder 的递归函数,用于中序遍历整棵二叉树。在每个节点处,我们先递归遍历左子树,然后将当前节点的值与 prev 进行比较。如果当前节点的值小于等于 prev,则说明当前二叉树不是二叉搜索树,将 isValid 设置为 false 并返回。否则,我们将 prev 更新为当前节点的值,然后递归遍历右子树。
最后,我们调用 inorder 函数开始中序遍历整棵二叉树,并返回 isValid。
复杂度分析
- 时间复杂度为 O(n)
对于每个节点而言,inorder 函数最多被调用一次,因此该算法的时间复杂度取决于遍历整棵二叉树所需的时间。由于每个节点最多只会被遍历一次,因此遍历整棵二叉树所需的时间是 O(n)。其中,n 是二叉树中节点的个数。
- 空间复杂度为 O(n)
递归调用 inorder 函数所需的栈空间取决于递归栈的深度,而递归栈的深度又取决于二叉树的高度。在最坏情况下,二叉树的形态为一条链,递归栈的深度达到 n,因此空间复杂度为 O(n)。