目录
任务
530. 二叉搜索树的最小绝对差
给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。
差值是一个正数,其数值等于两值之差的绝对值。
思路
最简单的做法是讲二叉搜索树转为有序数组(中序序列),然后遍历数组求最小绝对差。
这里我使用递归的思路来进一步熟悉递归。由二叉搜索树的特性,采用中序遍历,过程中使用pre指针,判断pre指针指向的元素和遍历到的当前元素的差值,最终保存最小的差值。#### 注意
使用了成员变量本题变得比较简单和直观,第一次做的时候,用的是传参,由于python中的传参是传值,疯狂出错= =,非常绕,而且当是可变类型变量时,与之前的List作为参数产生对比,之前是直接对List的内容进行操作(路径之和II等,append),所以每层递归操作的都是同一个List,而本题如果采用传参,语句中的pre相当于局部变量,每一层的pre都之和自己有关,因此需要作为left,right返回值,才能达到修改。此外还有个minDelta,也要用返回值操作
class Solution:
def __init__(self):
self.minDelta = float('inf')
self.pre = None
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
self.dfs(root)
return self.minDelta
def dfs(self,node):
if not node: return
self.dfs(node.left)
if self.pre:
self.minDelta = min(self.minDelta,node.val - self.pre.val)
self.pre = node
self.dfs(node.right)
501. 二叉搜索树中的众数
给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。
如果树中有不止一个众数,可以按 任意顺序 返回。
思路
第一反应同样是直接转中序数组,然后用map统计频率,再排序。
如果采用递归的方法做,该如何做呢?这个只遍历一遍挺难想,比较巧妙,特别是用maxSize比较难想到
思路是,中序遍历的过程中,遍历到节点该如何统计呢?
因为涉及到前后比较,还是使用pre指针,由于中序遍历值有序,所以在中序中的处理步骤如下
- pre为空时,就是node到达中序的第一个节点,count = 1。
- pre.val与node.val相等时,count += 1
- 不等时,count = 1
- 如果count == maxSize ,则将该节点的值加入到结果中
- 如果count > maxSize,则先清空结果数组,再将新节点的值加入到结果中
- 别忘了pre = node 来移动pre哦, node是由于递归结构自动移动的(中序)
class Solution:
def __init__(self):
self.maxSize = 0
self.pre = None
self.count = 0
self.res = []
def findMode(self, root: Optional[TreeNode]) -> List[int]:
self.inorder(root)
return self.res
def inorder(self,node):
if not node:return
self.inorder(node.left)
if not self.pre:
self.count= 1
elif self.pre.val == node.val:
self.count+=1
else: self.count = 1
if self.count == self.maxSize:
self.res.append(node.val)
if self.count > self.maxSize:
self.maxSize = self.count
self.res.clear()
self.res.append(node.val)
self.pre = node
self.inorder(node.right)
236. 二叉树的最近公共祖先
思路
由于要知道自己的后面(左子树和右子树)有没有p或者q,即收集后续的信息,返回给上层,采用后序遍历的方法。同样好写不好想的一题。
- 空节点直接返回空
- 如果节点是p或者q,返回自己给上层 (这里隐藏了一个自己是父节点的情况)
- 否则如果节点一边返回的是空,而另一边非空,则返回另一边的值给上层
- 否则如果节点为叶子,则返回None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
return self.dfs(root,p,q)
def dfs(self,node,p,q):
if not node: return None
if node == p or node == q: return node
left = self.dfs(node.left,p,q)
right = self.dfs(node.right,p,q)
if left and right: return node
elif not left and right: return right
elif left and not right: return left
else: return None
心得体会
今天知道了py中,成员变量在递归中比较好用,因为保存了状态,对于函数相当于全局变量,此后的递归中都会影响同样的变量。而由于py中的传参为传值,即使是可变类型,传的也是‘引用’的值,对于它本身来讲,每次调用函数都是参数都相当于是新的局部变量,但是可以修改可变参数的内容。今天的题目修改的是引用本身,所以就不能按照之前修改List内容的思路处理了。
而Cpp中传引用就比较好处理,其引用参数的地位和成员变量是一样的。