算法学习 day18 二叉树6

95 阅读5分钟

530. 二叉搜索树的最小绝对差

文章讲解

视频讲解

题目:给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 。

差值是一个正数,其数值等于两值之差的绝对值。

 

示例 1:

输入: root = [4,2,6,1,3]
输出: 1

解题思路

递归,中序遍历一遍二叉搜索树,当成有序数组,两两比较差值。

1 采用递归的方式进行中序遍历二叉搜索树。

2 在中序遍历的过程中,记录前一个节点的值,并计算当前节点值与前一个节点值的差值,更新最小差值。

3 由于二叉搜索树的中序遍历结果是一个有序序列,因此相邻节点的差值就是最小绝对差。

  • 时间复杂度:O(n) 每个节点都会被访问到,复杂度是O(n)。
  • 空间复杂度:O(n) 递归函数空间复杂度取决于递归栈的深度,最坏情况下二叉树为一条链时达到O(n)。
class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        self.result = float("inf") # 最小差值 
        self.prev = None # 前一个节点
        self.traverse(root)
        return self.result

    def traverse(self, root: Optional[TreeNode])->None:
        if not root:
            return
        
        self.traverse(root.left)
        
        # 中序位置,先更新差值,然后更新prev
        if self.prev:
            self.result = min(self.result, root.val - self.prev.val)
        
        self.prev = root
        self.traverse(root.right)

总结

注意本题必定有2个节点,否则需要讨论result没有答案的情况。

501. 二叉搜索树中的众数

文章讲解

视频讲解

题目:给你一个含重复值的二叉搜索树(BST)的根节点 root ,找出并返回 BST 中的所有 众数(即,出现频率最高的元素)。

如果树中有不止一个众数,可以按 任意顺序 返回。

假定 BST 满足如下定义:

  • 结点左子树中所含节点的值 小于等于 当前节点的值
  • 结点右子树中所含节点的值 大于等于 当前节点的值
  • 左子树和右子树都是二叉搜索树

 

示例 1:

输入: root = [1,null,2,2]
输出: [2]

示例 2:

输入: root = [0]
输出: [0]

提示:

  • 树中节点的数目在范围 [1, 104] 内
  • -105 <= Node.val <= 105

解题思路

由于是二叉搜索树,中序遍历元素是有序递增的,相同元素只会连续出现,所以只需要用记录当前元素的频率curFreq,最大的频率maxFreq;然后如果curFreq=maxFreq时候,将当前的root.val加入结果列表;如果curFreq>maxFreq时候,需要重置结果为[root.val]。

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        self.maxFreq = -1 # 最长序列长度
        self.curFreq = -1 # 当前元素的频率
        self.mode = []
        self.prev = None

        self.traverse(root)
        return self.mode
    
    def traverse(self,root: Optional[TreeNode]) -> List[int]:
        if not root:
            return
        
        self.traverse(root.left)
        # 更新频率:prev空时候更新max、cur、mode;非none时,判断当前元素和之前的是否相等。
        # prev空时初始化
        if self.prev is None:
            self.curFreq = 1
            self.maxFreq = 1
            self.mode = [root.val]

        # prev非空时,看看当前元素和之前的是否能接续
        else:
            if root.val == self.prev.val:
                self.curFreq += 1
                if self.curFreq == self.maxFreq:
                    self.mode.append(root.val)
                elif self.curFreq > self.maxFreq:
                    self.maxFreq = self.curFreq
                    self.mode = [root.val]
            else:
                # 不相等,重置cur
                self.curFreq = 1
                if self.curFreq == self.maxFreq: # 相等的时候追加,>时候重置
                    self.mode.append(root.val) # 追加
            

        # 更新指针
        self.prev = root
        
        self.traverse(root.right)

总结

注意可能存在多个频率相同的众数。curFreq == maxFreq时候追加,curFreq > maxFreq时候重置mode。

236. 二叉树的最近公共祖先

文章讲解

视频讲解

题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

 

示例 1:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3

示例 2:

输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

示例 3:

输入: root = [1,2], p = 1, q = 2
输出: 1

 

提示:

  • 树中节点数目在范围 [2, 105] 内。
  • -109 <= Node.val <= 109
  • 所有 Node.val 互不相同 。
  • p != q
  • p 和 q 均存在于给定的二叉树中。

解题思路

递归遍历左右子树,对于根节点root和p、q,有三种情况:

1 p在左边,q在右边,root是最近公共祖先

2 root不是p、q任何一个的公共祖先,返回None

3 p、q在root的同一侧,如果右子树无答案,返回左子树的公共祖先;如果左子树无答案,返回右边的。

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # base case:
        if not root:
            return None
        if root == p or root == q:
            return root
        
        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)

        # case1: left和right都有值,那就是root
        if left is not  None and right is not None:
            return root
        # case2:都没有公共祖先,none
        if left is None and right is None:
            return None

        # case3:在一侧
        return left if right is None else right

总结

注意base case如果root为p或q其中一个时候,最近的公共祖先只能是root。