530. 二叉搜索树的最小绝对差
直接对 BST 进行中序遍历,得到的结果就是一个递增的有序数组,再求解就非常容易了。
但其实可以利用 BST 的有序性,直接通过一次遍历解决问题。这里用到了之前的双指针。
普通递归
记录当前节点的上下限(根据之前的父节点方向记录)。
class Solution:
def limitMinDiff(self, node: Optional[TreeNode], lower: int, upper: int) -> int:
# node will not be None
curr_records = [upper - node.val, node.val - lower]
if node.left != None:
curr_records.append(node.val - node.left.val)
curr_records.append(self.limitMinDiff(node.left, lower, node.val))
if node.right != None:
curr_records.append(node.right.val - node.val)
curr_records.append(self.limitMinDiff(node.right, node.val, upper))
return min(curr_records)
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
return self.limitMinDiff(root, float("-inf"), float("inf"))
双指针
看到 BST 的第一反应一定是中序遍历,最大程度利用其单调性,同时通过 pre 指针来记录相邻的前一个节点,进行相关的操作。
class Solution:
def __init__(self):
self.minDiff = float("inf")
self.pre = None
def limitMinDiff(self, node: Optional[TreeNode]) -> None:
if node == None:
return
# left
self.limitMinDiff(node.left)
# middle
if self.pre != None:
if self.minDiff > node.val - self.pre.val:
self.minDiff = node.val - self.pre.val
self.pre = node
# right
self.limitMinDiff(node.right)
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
self.limitMinDiff(root)
return self.minDiff
501. 二叉搜索树中的众数
暴力算法非常直接,如果是一棵普通的树,用任意方式遍历整棵树然后生成 val: count
的 mapping,然后统计 count 最高的元素即可。但是暴力算法需要排序,
O
(
n
log
n
)
O(n\log{n})
O(nlogn) 的复杂度。
题目中给出的 BST 条件规定了单调性,众数又代表着只需要求最大值即可。这样的条件让我们能够一次遍历( O ( n ) O(n) O(n) 的复杂度)解决问题,思路与之前的单调数组一模一样。另外本题中 BST 允许重复元素。
BST 的所有题型,都要优先考虑中序遍历!最优利用 BST 的单调性。
同时考虑双指针!因为双指针能记录相邻两个元素的值,一个指向当前节点,一个指向之前的节点,能够很好解决 BST 中隔(很多)层记录上下限的问题。
class Solution:
def __init__(self):
self.count = 0
self.maxCount = 0
self.maxRecords = []
self.pre = None
def inorder_traverse(self, curr_node: Optional[TreeNode]) -> None:
if curr_node == None:
return
# left node
self.inorder_traverse(curr_node.left)
if self.pre == None or self.pre.val != curr_node.val:
self.count = 1
else:
self.count += 1
self.pre = curr_node
# middle
if self.count == self.maxCount:
self.maxRecords.append(curr_node.val)
if self.count > self.maxCount:
self.maxCount = self.count
self.maxRecords = [curr_node.val]
# right
self.inorder_traverse(curr_node.right)
def findMode(self, root: Optional[TreeNode]) -> List[int]:
self.inorder_traverse(root)
return self.maxRecords
236. 二叉树的最近公共祖先
查找两个节点的最近公共祖先,直觉上应该是一个自下而上的查找顺序(回溯!),所以应该使用后序遍历:根据子树的信息处理当前的中节点。
这里递归的思路是,当遇到了一个目标节点(p 或者 q),就返回该节点,否则返回 None。这一过程不断向上传递,直到有一个节点的左子树和右子树都显示遇到过目标节点,此时该节点即是两个目标节点的最近公共祖先。这么做的前提是二叉树中没有重复的元素。
另一种情况是,一个目标节点 p 是另一个目标节点 q 的祖先。这种情况下,之前传递的 q 节点会被 p 代替,p 会不断回溯到根节点,同样能返回正确答案。
注意,函数无需区分遇到的是 p 还是 q,重要的是遇到了目标节点。不断向上传递遇到目标节点的节点实际上是在进行回溯。
回溯解法
这种解法依然要遍历整棵树:即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值做逻辑判断。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root == None: # not meet the target, but at the end
return None
if root == p or root == q: # meet a target
return root
left_result = self.lowestCommonAncestor(root.left, p, q)
right_result = self.lowestCommonAncestor(root.right, p, q)
if left_result != None and right_result != None:
return root
if left_result != None and right_result == None:
return left_result
if left_result == None and right_result != None:
return right_result
暴力解法
求两个节点的最近公共祖先,很自然的想法是找到两个节点的各自的祖先们,然后从根节点开始同时遍历,找到最后一个公共祖先即可。
这样的解法中使用的是自上而下的前序遍历。
class Solution:
def findAncestors(self, root: Optional[TreeNode], ancestors: List[TreeNode], node: TreeNode) -> List[TreeNode]:
ancestors.append(root)
if root == node:
return ancestors
if root.left == None and root.right == None:
return []
result = []
if root.left != None:
result.extend(self.findAncestors(root.left, ancestors, node))
ancestors.pop()
if root.right != None:
result.extend(self.findAncestors(root.right, ancestors, node))
ancestors.pop()
return result
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
p_ancestors = self.findAncestors(root, [], p)
q_ancestors = self.findAncestors(root, [], q)
i = 0
while (i < len(p_ancestors) and i < len(q_ancestors)):
if p_ancestors[i] != q_ancestors[i]:
return p_ancestors[i-1]
i += 1
if i == len(p_ancestors):
return p_ancestors[-1]
else:
return q_ancestors[-1]