其实你看见二叉搜索树,把它和中序遍历联系起来就好了,二叉搜索树结构成立 == 中序遍历有序,这两者之间有等价关系,为什么?
因为l mid r的中序遍历顺序与二叉搜索树 左子树 < 中节点 < 右子树的结构性质吻合,这两者等价性的必要与充分我就不证明了,接下来放题目总结以及代码技巧。
双指针遍历思想:定义一个pre代表前节点,不断更新pre
leetcode98.验证二叉搜索树
中序遍历,当访问到当前节点时,两者对比,如果pre >= node,就返回False,不用遍历完整棵树,一旦发现False就直接层层返回。
其实这和在链表的操作没有本质区别,就是判定一个递增链表。
递归法1:不让空节点进入递归的风格
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
self.pre = None
def recursion(node):
#不让空节点进入递归
#左
if node.left:
result_l = recursion(node.left)
#只要有不符合条件的,就直接返回False,不用继续遍历整棵树
if not result_l:
return False
#中
if self.pre and self.pre.val >= node.val:
return False
#更新pre节点,记录前一个节点
self.pre = node
#右
if node.right:
result_r = recursion(node.right)
if not result_r:
return False
#如果都符合,向上层函数返回True
return True
return recursion(root)
递归法2:允许空节点进入递归的风格
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
self.pre = None
def inorder_traversal(node):
#终止条件改为空节点向上层直接返回True
if not node:
return True
result_l = inorder_traversal(node.left)
if not result_l:
return False
if self.pre and self.pre.val >= node.val:
return False
self.pre = node
result_r = inorder_traversal(node.right)
if not result_r:
return False
return True
return inorder_traversal(root)
迭代法:用栈模拟中序遍历
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
stk = []
stk.append((root, False))
pre = None
while stk:
(node, is_visited) = stk.pop()
if not is_visited:
if node.right:
stk.append((node.right, False))
stk.append((node, True))
if node.left:
stk.append((node.left, False))
else:
if pre and pre.val >= node.val:
return False
pre = node
return True
leetcode530.二叉搜索树的最小绝对差
同样采用双指针,记录前一个节点,不断更新差值,直到遍历完整棵树(打擂台的方式找最小值)
递归法:
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
self.pre = None
self.res = float('inf')
def inorder_traversal(node):
if node.left:
inorder_traversal(node.left)
if self.pre:
delta = node.val - self.pre.val
self.res = min(self.res, delta)
self.pre = node
if node.right:
inorder_traversal(node.right)
inorder_traversal(root)
return self.res
迭代法:
同样也有迭代法,不重复写了
leetcode.501二叉搜索树种的众数
直观想法,我遍历一遍存到字典里,然后找字典value最大对应的keys就行,不过这就需要额外O(n)的空间,以及需要多遍历一次字典的时间复杂度O(n)。
是否可以一次遍历二叉搜索树就找到答案?
思路如下:1、维护一个max_count(代表目前众数的数量)
2、中序遍历二叉搜索树,该顺序遍历是有序的,那对于一个有序数组,我同样用一个pre指针记录前节点,如果pre.val == cur.val,那我计数count+1,如果pre.val != cur.val,那count恢复为1。更新完count之后,count与max_count作比较
3、如果count == max_count,在res列表里加入当前节点值
如果count > max_count,把res列表清空(众数更新,之前的数作废),再加入
当前节点的值
递归法:
class Solution:
def findMode(self, root: Optional[TreeNode]) -> List[int]:
self.count = 1
self.max_count = 1
self.pre = None
res = []
def inorder_traversal(node):
if not node:
return
inorder_traversal(node.left)#left
#mid
if self.pre:
if self.pre.val == node.val:
self.count += 1
else:
self.count = 1
if self.count == self.max_count:
res.append(node.val)
elif self.count > self.max_count:
self.max_count = self.count
#先clear
res.clear()
res.append(node.val)
#第一个节点要加进res
else:
res.append(node.val)
self.pre = node
inorder_traversal(node.right)#right
inorder_traversal(root)
return res
迭代法:
class Solution:
def findMode(self, root: Optional[TreeNode]) -> List[int]:
res = []
stk = []
pre = None
max_count = 1
count = 1
stk.append((root, False))
while stk:
(node, is_visited) = stk.pop()
if not is_visited:
if node.right:
stk.append((node.right, False))
stk.append((node, True))
if node.left:
stk.append((node.left, False))
#在这个逻辑部分,才是真正去处理节点了,所以在这部分修改了pre
#代表我真的遍历并处理了这个节点
else:
if pre:
if pre.val == node.val:
count += 1
else:
count = 1
if count == max_count:
res.append(node.val)
elif count > max_count:
max_count = count
res.clear()
res.append(node.val)
else:
res.append(node.val)
pre = node
return res
leetcode.538把二叉搜索树转换为累加树
中序是左中右,这题反过来,右中左遍历,然后利用pre做累加就行
递归法:
class Solution:
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
self.pre = None
def right_mid_left_traversal(node):
if not node:
return
right_mid_left_traversal(node.right)
if self.pre:
node.val += self.pre.val
self.pre = node
right_mid_left_traversal(node.left)
right_mid_left_traversal(root)
return root
迭代法:
class Solution:
def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return None
stk = []
stk.append((root, False))
pre = None
while stk:
(node, is_visited) = stk.pop()
#入栈顺序 left mid right
if not is_visited:
if node.left:
stk.append((node.left, False))
stk.append((node, True))
if node.right:
stk.append((node.right, False))
else:
if pre:
node.val += pre.val
pre = node
return root