给定一个二叉树,判断其是否是一个有效的二叉搜索树。假设一个二叉搜索树具有如下特征:
- 节点的左子树只包含小于当前节点的数。
- 节点的右子树只包含大于当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
示例 1:
输入:
2
/ \
1 3
输出: true
示例 2:
输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4
二叉树遍历性质的应用:根据二叉搜索树的定义以及二叉树的中序遍历知道,它的中序遍历结果是升序排列的,因此我们只需要得到中序遍历结果,然后验证是否是升序排列即可。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
res = []
def inOrder(root):
if root == None:
return None
inOrder(root.left)
res.append(root.val)
inOrder(root.right)
inOrder(root)
# 如果二叉树中包含相同val的节点,或者中序遍历的结果不是升序,那么不是合法的二叉搜索树
if len(set(res)) != len(res) or sorted(res) != res:
return False
else:
return True
上面采用了先中序遍历获取给定二叉树的遍历结果,然后根据二叉搜索树中序遍历结果为升序排列的性质,判断遍历结果是否满足来决定给定二叉树的合法性。
其实,我们只需一个临时节点preNode
来记录当前遍历节点的前一个节点即可,在中序遍历的过程中进行判断,而无需额外的存储空间:
- 如果
preNode
为null
,表示此时遍历的是左子树的最左节点,直接将其赋给preNode
,即preNode = root
- 否则,判断当前遍历的节点
val
和preNode.val
的大小情况。如果root.val < preNode.val
,那么必然不是合法的二叉搜索树,直接返回false
对左子树和右子树递归进行上述的过程。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode preNode;
public boolean isValidBST(TreeNode root) {
if (root == null)
return true;
//访问左子树
if (!isValidBST(root.left))
return false;
//访问当前节点:如果当前节点小于等于中序遍历的前一个节点直接返回false。
if (preNode != null && preNode.val >= root.val)
return false;
preNode = root;
//访问右子树
if (!isValidBST(root.right))
return false;
return true;
}
}