Day18 第六章 二叉树Part6

任务

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指针,由于中序遍历值有序,所以在中序中的处理步骤如下

  1. pre为空时,就是node到达中序的第一个节点,count = 1。
  2. pre.val与node.val相等时,count += 1
  3. 不等时,count = 1
  4. 如果count == maxSize ,则将该节点的值加入到结果中
  5. 如果count > maxSize,则先清空结果数组,再将新节点的值加入到结果中
  6. 别忘了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中传引用就比较好处理,其引用参数的地位和成员变量是一样的。

posted @ 2024-08-03 13:38  haohaoscnblogs  阅读(16)  评论(0)    收藏  举报