一、530.二叉搜索树的最小绝对差
需要领悟一下二叉树遍历上双指针操作,优先掌握递归题目链接/文章讲解:代码随想录
视频讲解:二叉搜索树中,需要掌握如何双指针遍历!| LeetCode:530.二叉搜索树的最小绝对差_哔哩哔哩_bilibili
1. 直白想法
采用中序遍历,将这棵树转变为一个递增的有序数组,再对数组进行遍历。计算相邻两个数之间的差值,返回最小的绝对差。
2. 双指针法
在直白想法的基础上优化,通过定义一个指针指向前一个节点,另一个指针指向当前节点,用两个指针相减直接得到绝对差,就不需要将树转化为数组再进行遍历了。
(1)定义一个变量result记录相邻节点的最小绝对差,将其初始化为一个最大值。定义一个指针pre,将其初始化为None。
(2)定义函数的参数和返回值。因为本题定义了全局变量result和pre,所以递归函数不需要返回值。传入cur,作为当前遍历的节点。
(3)确定终止条件。遍历到当前节点为空,不需要返回值,所以只写一个return。
(4)单层递归遍历。本题采用中序遍历,先向左遍历;再处理中间节点,如果pre节点不为空,那么就可以记录cur和pre节点的差值,更新result采用min函数,取差值和原始result中间的最小值,最后为了使cur和pre始终紧密相连,所以更新pre指向cur;接下来可以向右递归。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def __init__(self):
self.result = float('inf')
self.pre = None
def traversal(self, cur):
if cur is None:
return
# left:
self.traversal(cur.left)
# middle:
if self.pre is not None:
self.result = min(self.result, cur.val-self.pre.val)
self.pre = cur
# right:
self.traversal(cur.right)
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
self.traversal(root)
return self.result
二、501.二叉搜索树中的众数
和 530差不多双指针思路,不过 这里涉及到一个很巧妙的代码技巧。
1. 双指针法
(1)定义pre指针,找到当前遍历节点的前一个节点;定义count,记录元素出现的频率;定义max_count,记录当前遍历节点中出现频率最高的;定义结果集数组result,用于存放结果集。
(2)定义递归函数,传入的是二叉树根节点,返回值为void,因为遍历整个二叉树,并且在遍历过程中直接对元素进行统计,结果也存放在result里了,因此不需要返回值。
(3)终止条件为cur遇到空,直接返回即可。
(4)中序遍历:
左:直接递归遍历;
中:1)if:如果pre指针为null,即递归遍历的第一个元素,因此count等于1,也就是该元素目前出现的频率为1;elif:如果pre指针指向的元素等于cur指针指向的元素,那么count+=1,也就是这个元素出现的频率加1。else:说明pre和cur不相等,所以count变回1;
2)递归:pre=cur;
3)收获结果:如果count等于max_count,那么将其放进结果集;如果count大于max_count,那么将max_count更新为count,由于max_count更新,那么说明之前结果集的元素不是我们真正想要的结果,所以清空result结果集,再将当前结果放进结果集。这样完成了result的实时更新。
右:向右遍历,最后返回。
2. 代码实现
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def __init__(self):
self.result = []
self.pre = None
self.count = 0
self.max_count = 0
def traversal(self, cur):
if cur is None:
return
# left:
self.traversal(cur.left)
# middle:
if self.pre is None:
self.count = 1
elif cur.val == self.pre.val:
self.count += 1
else: self.count = 1
self.pre = cur
if self.count == self.max_count:
self.result.append(cur.val)
if self.count > self.max_count:
self.max_count = self.count
self.result = []
self.result.append(cur.val)
# right:
self.traversal(cur.right)
def findMode(self, root: Optional[TreeNode]) -> List[int]:
self.traversal(root)
return self.result
三、236. 二叉树的最近公共祖先
本题其实是比较难的,可以先看我的视频讲解
1. 解题思路
自底向上遍历,第一个交汇的节点就是最近公共祖先。而二叉树只能从根节点开始遍历,但回溯的过程可以让我们从底向上去遍历树。
2. 后序遍历
后序遍历:左右中的顺序,左/右中有p或q就向上返回,因此左子树中如果不为空,说明包含p或q,右子树不为空说明包含q或p,那么中间的这个节点就是最近的公共祖先。
3. 代码实现
(1)定义函数traversal,返回值为二叉树的公共祖先,所以返回节点TreeNode。传入参数为根节点、p和q。
(2)终止条件:遍历的节点为空,直接返回null;如果root等于p或q,则将节点返回。
(3)后序遍历:
左:向左遍历,传入left和q、p,告诉我们左子树是否存在p或q;
右:向右遍历,传入right和q、p,告诉我们右子树是否存在p或q;
中:如果左且右不为空,那么说明二者出现了p或q;如果左为空且右不为空,那么说明右子树出现了p或q,将右向上返回;如果左不为空且右为空,那么说明左子树出现了p或q,将左向上返回;左右均为空,返回null。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root is None: return None
if root == q or root == p: return root
# left:
left = self.lowestCommonAncestor(root.left, p, q)
# right:
right = self.lowestCommonAncestor(root.right, p, q)
# middle:
if left is None and right is None: return None
if left is None and right is not None: return right
if left is not None and right is None: return left
if left is not None and right is not None: return root