题目
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
- 就是看一颗是是否满足二叉搜索树。
思路
-
剑指里面有一道是判断一个序列是否是某二叉搜索树的中续遍历。一种简单的思路就是先中续遍历一遍,然后用剑指的办法判断。
-
但经验告诉我,如果该树是二叉搜索树,我们需要走完所有的节点才能确定。但一旦某个节点不满足二叉搜索子树,我们是直接能得出整棵树都不是二叉搜索树。也就是提前阻断法,对于不是二叉搜索树的情况下,不必走完所有节点。比第一种办法的效率更加高。
-
具体做法是。采用后续遍历,在递归中,判断该节点为根节点的子树是否是二叉搜索树。如果是,则返回True,该子树的最大值,该子树的最小值
-
如何判断子树是否是二叉搜索树?如果对左子树遍历得到的flag为True,且当前节点值大于等于(不允许有重复节点)左子树的最大值,则左分支没问题;同理判断右分支。
-
最后结合当前节点的值,重新计算最小值和最大值
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
def walk(p):
if not p:
return True, -float('inf'), float('inf')
val = p.val
left, max_val_1, min_val_1 = walk(p.left)
if not left or val <= max_val_1: # 小于等于,等于不能缺少
return False, 0, 0
right, max_val_2, min_val_2 = walk(p.right)
if not right or val >=min_val_2:
return False, 0, 0
max_val = max(val, max_val_1, max_val_2)
min_val = min(val, min_val_1, min_val_2)
return True, max_val, min_val
flag, _, _ = walk(root)
return flag
其他方法
原来先序遍历和中序遍历都能提前阻断。
自己看了题解,写了一种中序遍历的思路,就是用path记录中序遍历的结果,当前节点和之前的节点比较大小。
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
path = []
def walk(p):
nonlocal path
if not p:
return True
flag = walk(p.left)
if not flag:
return False
if len(path) == 0:
path.append(p.val)
else:
if path[-1] < p.val:
path.append(p.val)
else:
return False
flag = walk(p.right)
return flag
flag = walk(root)
return flag