代码随想录|Day18|二叉树07|530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先

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

本题和 98.验证二叉搜索树 的逻辑类似,由于二叉搜索树的特性,中序遍历的结果将是单调递增的,最小绝对差一定发生在遍历的相邻节点。我们可以遍历完后,再对得到的中序数组进行处理,或者在遍历时直接进行处理。

思路1:中序遍历二叉搜索树,得到一个单调递增的数组,接着从中寻找最小绝对差。

class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        # 中序遍历
        def inorderTraversal(node):
            if not node:
                return []
            left = inorderTraversal(node.left)
            right = inorderTraversal(node.right)
            return left + [node.val] + right

        inorder = inorderTraversal(root)
        min_diff = float('inf')
        
        for i in range(1, len(inorder)):
            min_diff = min(min_diff, inorder[i]-inorder[i-1])

        return min_diff

 思路2:中序遍历的过程中,计算相邻遍历节点的绝对差,维护一个最小绝对差。我们可以定义一个指针 prev,指向当前节点的前一节点。

class Solution:
    def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
        # prev在被更新为第一个遍历节点值之前,
        # 会先用来被计算一次 min_diff(此并非树中任何节点之间的差值,因为prev此时并不是某一节点)
        # 为了确真正的节点差值能被正确记录,初始化prev为一个很小的负数
        # 这样 min_diff 就会被初始化为一个一个很大的数值
        self.prev = -float('inf')
        self.min_diff = float('inf')
    
        def inorderTraversal(node):
            if not node:
                return
            inorderTraversal(node.left)
            self.min_diff = min(self.min_diff, node.val - self.prev)
            self.prev = node.val
            inorderTraversal(node.right)
        
        inorderTraversal(root)
        return self.min_diff

501.二叉搜索树中的众数

暴力:遍历二叉树,使用哈希表记录元素出现频率,按照频率排序,输出元素。

class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        freq_map = defaultdict(int)
        modes = []

        def postorder(node, freq_map):
            if not node:
                return
            freq_map[node.val] += 1
            postorder(node.left, freq_map)
            postorder(node.right, freq_map)
        # 遍历二叉树,填充字典
        postorder(root, freq_map)
        # 排序字典
        max_freq = max(freq_map.values())
        # 收集出现频率最高的数字
        modes = [k for k, v in freq_map.items() if v == max_freq]
        return modes

思路:利用二叉搜索树的特性,同样是在遍历过程中统计每个元素出现的频率,并维护一个最大频率。由于我们需要完整遍历整个树才能确切知道最大频率,因此这里采取这样的措施:如果当前记录的最大频率被更新,则清空已收集的元素,重新收集。

这个过程可以分为以下几步:

  1. 如果当前节点值等于前一个节点值(prev),currCount加一,因为这意味着当前值与之前的值相同,我们正在计算这个特定值的出现次数。
  2. 如果当前节点值不等于前一个节点值,这意味着我们开始计算一个新值的出现次数,所以需要将currCount重置为1。
  3. 每次更新currCount后,比较它与maxCount。根据这个比较的结果:
  • 如果currCount大于maxCount,这意味着我们找到了一个新的频率更高的值。因此,需要更新maxCount为新的currCount,清空众数列表,并将当前节点值加入众数列表。
  • 如果currCount等于maxCount,这意味着当前节点值的出现频率与已知的最高频率相同,所以需要将当前节点值加入到众数列表中,但不需要清空原有的众数列表。
  • 如果currCount小于maxCount,则不需要对maxCount或众数列表做任何更改。
class Solution:
    def findMode(self, root: Optional[TreeNode]) -> List[int]:
        self.currCount = 0
        self.maxCount = 0
        self.prev = None
        self.modes = []

        def inorder(node):
            if not node:
                return
            # 左
            inorder(node.left)
            # 中
            if node.val == self.prev:
                self.currCount += 1
            else:
                self.currCount = 1
                self.prev = node.val

            if self.currCount > self.maxCount:
                self.maxCount = self.currCount
                self.modes = [node.val]
            elif self.currCount == self.maxCount:
                self.modes.append(node.val)
            # 右
            inorder(node.right)
        
        inorder(root)
        return self.modes

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

本题需要判断左右子树的情况,才能确定此节点是否为公共祖先。因此采用后序遍历。

思路是从根节点开始,递归地在左右子树中查找指定的两个节点。对于每个节点来说,可能存在以下几种情况:

  • 如果当前节点就是两个节点中的一个,那么它就可能是最近公共祖先。
  • 如果当前节点的左右子树分别包含这两个节点,那么当前节点就是它们的最近公共祖先。
  • 如果这两个节点都位于当前节点的同一侧(都在左子树或都在右子树),那么最近公共祖先将在那一侧的子树中。
class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        # 递归终止条件
        # 空节点,或者找到了p或q
        if not root or root == p or root == q:
            return root
        # 在左子树中递归寻找p或q
        left = self.lowestCommonAncestor(root.left, p, q)
        # 在右子树中递归寻找p或q
        right = self.lowestCommonAncestor(root.right, p, q)
        # 如果左子树和右子树各自找到了p和q(即left和right都非空),
        # 那么当前节点就是最近公共祖先
        if left and right:
            return root
        # 如果左子树为空,那么p和q都在右子树中,返回右子树的结果
        if not left:
            return right
        # 如果右子树为空,那么p和q都在左子树中,返回左子树的结果
        if not right:
            return left
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值