代码随想录算法训练营第十六天(二叉树篇)|Leetcode530二叉搜索树的最小绝对差,Leetcode501二叉搜索树中的众数,Leetcode236二叉树的最近公共祖先
Leetcode 530 二叉搜索树的最小绝对差
题目链接: 二叉搜索树的最小绝对差
给定一棵二叉搜索树的根节点,返回该二叉搜索树中任意两个节点之间差值绝对值的最小值。任意两个节点的值都不相同。
思路: 根据二叉搜索树的性质,根节点严格大于左子树中的所有节点,严格小于右子树中的所有节点。因此,二叉搜索树的中序遍历数组为单调递增数组。我们只需要通过中序遍历得到二叉搜索树的中序遍历数组,随后再找出数组中两个元素差值的最小值即可。
具体代码实现:
# 在具体实现时,我们可以不将中序遍历的结果保存到数组中,原地对节点的值进行比较
class Solution:
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
# 利用带有标志位的迭代法完成中序遍历操作
from collections import deque
myQueue = deque()
myQueue.append([root, False])
# 将前一个节点初始化为空
pre = None
minDiff = float('inf')
while myQueue:
node, visited = myQueue.pop()
# 当收获相应节点时,将节点与前一个遍历过的节点值进行比较,不断更新最小差值
if visited:
cur = node
if pre is None:
pass
# 动态更新节点之间的最小差值
elif cur.val - pre.val < minDiff:
maxDiff = cur.val - pre.val
# 将当前收获的节点进行保存,供后续比较用
pre = cur
continue
if node.right:
myQueue.append([node.right, False])
myQueue.append([node, True])
if node.left:
myQueue.append([node.left, False])
return minDiff
Leetcode 501 二叉搜索树中的众数
题目链接: 二叉搜索树中的众数
给定一棵二叉搜索树(树中可能出现值重复的节点),找出树中所有出现次数最多的节点,并返回它们的值。如果树中出现的值有多个,按照任意顺序返回所有值的列表
思路:
暴力法: 遍历二叉树,利用字典记录各个值出现的次数,将出现次数最多的元素加入到列表中,最终返回相应列表即可。
中序遍历原地比较法: 我们也可以利用二叉搜索树的性质,由于中序遍历数组递增,我们可以通过中序遍历遍历整棵二叉树,在遍历过程中,记录元素出现的次数,将出现次数最多的元素加入到列表中并返回
具体代码实现
# 暴力法
class Solution:
def traversal(self, root: Optional[TreeNode], freqMap: dict) -> None:
if root is None:
return
self.traversal(root.left, freqMap)
freqMap[root.val] = freqMap.get(root.val, 0) + 1
self.traversal(root.right, freqMap)
def findMode(self, root: Optional[TreeNode]) -> List[int]:
freqMap = dict()
self.traversal(root, freqMap)
maxFreq = max(freqMap.values())
result = []
for num, freq in freqMap.items():
if freq == maxFreq:
result.append(num)
return result
# 中序遍历原地比较法
class Solution:
def findMode(self, root: Optional[TreeNode]) -> List[int]:
from collections import deque
myQueue = deque()
pre = None
maxCount = 0
result = []
myQueue.append([root, False])
while myQueue:
node, visited = myQueue.pop()
if visited:
cur = node
if pre is None:
count = 1
elif cur.val == pre.val:
count += 1
else:
count = 1
pre = cur
if count == maxCount:
result.append(cur.val)
if count > maxCount:
maxCount = count
result = [cur.val]
continue
if node.right:
myQueue.append([node.right, False])
myQueue.append([node, True])
if node.left:
myQueue.append([node.left, False])
return result
Leetcode 236 二叉树的最近公共祖先
题目链接: 二叉树的最近公共祖先
给定一棵二叉树的根节点和两个特定节点,要求找出这两个节点在二叉树中的最近公共祖先。注意,这两个节点中的任意一个均有可能为这两个节点的最近公共节点本身。
Example1:
3
/ \
5 1
/ \ / \
6 2 0 8
5
和1
的最近公共祖先是3
,5
和2
的最近公共祖先为5
思路: 由于我们需要找出两个节点的最近公共祖先,我们需要从叶子向根节点向上寻找,返回相应结果。后序遍历正好可以满足我们自底向上进行遍历的需求。
明确了遍历方式,接下来是具体的代码实现方式,我们通过递归三部曲进行分析:
- 递归函数的参数与返回值:
递归函数的参数为当前正在遍历的节点与两个给定的节点。返回值类型为二叉树节点 - 递归终止条件:
若当前节点为空时,终止递归,并返回空节点;若当前节点为给定的节点,则返回相应节点 - 每层递归所做操作:
判断当前节点的左子树和右子树中是否存在相应给定的节点,若给定的两个节点分别存在与以当前节点为根节点的左子树和右子树中,则返回当前节点。否则将左子树或右子树中找到的节点向上传递。
具体代码实现
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 当前节点为空或为两个给定节点之一,向上返回结果
if root is None or root == p or root == q:
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
return left if left is not None else right