題目
給定一個二叉樹,判斷其是否是一個有效的二叉搜索樹。
假設一個二叉搜索樹具有如下特徵:
節點的左子樹只包含小於當前節點的數。
節點的右子樹只包含大於當前節點的數。
所有左子樹和右子樹自身必須也是二叉搜索樹。
- 就是看一顆是是否滿足二叉搜索樹。
思路
-
劍指裏面有一道是判斷一個序列是否是某二叉搜索樹的中續遍歷。一種簡單的思路就是先中續遍歷一遍,然後用劍指的辦法判斷。
-
但經驗告訴我,如果該樹是二叉搜索樹,我們需要走完所有的節點才能確定。但一旦某個節點不滿足二叉搜索子樹,我們是直接能得出整棵樹都不是二叉搜索樹。也就是提前阻斷法,對於不是二叉搜索樹的情況下,不必走完所有節點。比第一種辦法的效率更加高。
-
具體做法是。採用後續遍歷,在遞歸中,判斷該節點爲根節點的子樹是否是二叉搜索樹。如果是,則返回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