今天做的都是二叉搜索树,主要解题思路
- 中序遍历+递归
- 双指针
530.二叉搜索树的最小绝对差
- 自己写的时候用的中序遍数组+求差
- 题解的方法还加了一个双指针,大概意思就是记录cur和pre,因为是中序遍历,因此pre就是递增序列中cur的前一个。需要注意一定是中序遍历,cur的处理在left和right中间。
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
# 二叉搜索树
# 最小差值
# 1. 中序遍历转换为数组+求差
self.diff = []
self.traversal(root)
return min(self.diff)
# 返回最小值的话,需要知道左的最大值和右的最小值
def traversal(self, root):
if not root:
return []
left = self.traversal(root.left)
right = self.traversal(root.right)
if len(left) > 0: self.diff.append(root.val - left[-1])
if len(right) > 0: self.diff.append(right[0] - root.val)
return left + [root.val] + right
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
# 二叉搜索树
# 最小差值
# 1. 中序遍历转换为数组+求差
self.diff = []
self.pre = None
self.cur = root
self.result = float('inf')
self.traversal(root)
return self.result
# 返回最小值的话,需要知道左的最大值和右的最小值
def traversal(self, root):
if not root:
return []
self.traversal(root.left)
if self.pre:
self.result = min(root.val - self.pre.val, self.result)
self.pre = root
self.traversal(root.right)
501.二叉搜索树中的众数
- 本来以为和前一题一模一样,双指针。但是写的时候出了很多错,写了一堆if else,很离谱
- 看了一下题解思路应该是差不多的,细节上稍有不同
class Solution:
def findMode(self, root: Optional[TreeNode]) -> List[int]:
# 双指针的话,记录前一个,如果一样的话count+1,并且和max_count做对比
self.pre = None
self.max_count = 1
self.count = 1
self.res = []
self.traversal(root)
# print(self.max_count)
return self.res
def traversal(self, cur):
if cur is None:
return
self.traversal(cur.left)
print(self.pre, cur.val)
if self.pre:
# print(self.pre.val, cur.val)
if self.pre.val == cur.val:
self.count += 1
else:
self.count = 1
if self.count > self.max_count:
self.res = [cur.val]
self.max_count = self.count
elif self.count == self.max_count:
self.res.append(cur.val)
else: self.res = [cur.val]
self.pre = cur
self.traversal(cur.right)
- 如果不是二叉搜索树,暴力解法就是遍历一遍二叉树,得到每个数字的频率,再求最大的。
- dict的最大值max(map.values())
- key, freq in freq_map.items()遍历dict
max_freq = max(freq_map.values())
for key, freq in freq_map.items():
if freq == max_freq:
result.append(key)
return result
236. 二叉树的最近公共祖先
- 这题之前应该做过,但完全想不起来之前咋做的了(看了一下提交记录,感觉要么是乱做的,要么是看题解做的。。。)
- 现在用的递归,很复杂
- 题解里的思路:没看过还是挺难写出来的
- 求最小公共祖先,需要从底向上遍历,那么二叉树,只能通过后序遍历(即:回溯)实现从底向上的遍历方式。
- 在回溯的过程中,必然要遍历整棵二叉树,即使已经找到结果了,依然要把其他节点遍历完,因为要使用递归函数的返回值(也就是代码中的left和right)做逻辑判断。
- 要理解如果返回值left为空,right不为空为什么要返回right,为什么可以用返回right传给上一层结果。
- 可以说这里每一步,都是有难度的,都需要对二叉树,递归和回溯有一定的理解。
- 本题没有给出迭代法,因为迭代法不适合模拟回溯的过程。理解递归的解法就够了。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
self.p = p
self.q = q
self.res = None
self.traversal(root)
return self.res
def traversal(self, cur):
if not cur:
return False, False
find_p_left, find_q_left = self.traversal(cur.left)
find_p_right, find_q_right = self.traversal(cur.right)
print(cur.val, find_p_left, find_p_right, find_q_left, find_q_right)
if (find_p_left or find_p_right or (cur.val == self.p.val)) and (find_q_left or find_q_right or (cur.val == self.q.val)):
if not self.res:
self.res = cur
return (find_p_left or find_p_right or (cur.val == self.p.val)), (find_q_left or find_q_right or (cur.val == self.q.val))
题解的写法:
- 返回值只有一个,也就是最终需要的祖先
- 当遇到p和q的时候,返回p和q
- 在处理当前节点的时候,如果左右分别都有返回值,那自身一定是最近公共祖先,返回自身。此时相当于合并了两个有返回值的节点,这之后一定只有一边有返回值。
- 如果左右只有一边有返回值,有两种情况,一个是确实只遇到了一个,一个是两个返回值已经合并。第二种情况的话,应该继续返回之前的返回值,因为那个已经是找到的最近公共祖先了。也就是返回非空的那个。此时考虑第一种情况,也没有问题,因为第一种情况只需要有返回值就可以了,不需要关注返回的具体值,之后合并的时候才需要考虑。
- 如果自身是最近公共节点,那么由于是后序遍历,后一个返回值会覆盖前一个,相当于做了一次合并,这之后只有这一个返回值会回溯到顶,因此也可以。
class Solution:
def lowestCommonAncestor(self, root, p, q):
if root == q or root == p or root is None:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left is not None and right is not None:
return root
if left is None and right is not None:
return right
elif left is not None and right is None:
return left
else:
return None