代码随想录|Day11|栈与队列03|239. 滑动窗口最大值、347. 前 K 个高频元素

239. 滑动窗口最大值

暴力:遍历整个数组,对于每个窗口,遍历找出最大值,时间复杂度为 O(n * k)

思路:主要优化寻找窗口最大值的过程,可以实现 O(1) 的时间复杂度,整个算法的时间复杂度就降低为 O(n * 1) = O(n)。实现的方法是构造单调队列,队内元素从大到小排列,队列首位即最大值。

每次滑动窗口,我们需要考虑两点:
1. 队首元素是否需要出队?保证队内的元素都属于当前窗口,而不是上个窗口。

2. 队尾元素是否需要移除?保证队列的单调性。

假设窗口长度为 k,现在要让 indexi 的元素入队。

让我们先考虑第一点:

新元素入队,意味着窗口右端元素的 indexi,那么窗口左端元素的 index 应该为 i - k + 1。如果队首元素的 index < i - k + 1,则说明其不属于当前窗口,它会被新入队元素挤走。

接下来考虑第二点:

将新元素与队尾元素对比,如果队尾元素更小,则出队。重复此过程直到新元素小于队尾元素,此时新元素应该入队,形成新的单调队列。

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:

        # 这里选择将 index 存入队列
        result = []
        window = deque()
        # 遍历数组
        for i in range(len(nums)):
            # 处理窗口左端,查看是否要出队
            if window and window[0] < i - k + 1:
                window.popleft()
            # 处理窗口右端,查看是否要弹出一些元素后入队
            while window and nums[i] > nums[window[-1]]:
                window.pop()
            window.append(i)
            # 检查完窗口两端后,考虑收集结果
            # 但在数组 nums 的开始部分,窗口还未形成前,无法收集元素。
            if i >= k - 1:
                result.append(nums[window[0]])
        
        return result
# 时间复杂度:
# 每个元素最多入队一次,出队一次,两个操作都为O(1)
# 总时间复杂度为O(n)

347. 前 K 个高频元素

暴力:哈希表记录所有元素的频率,然后对频率排序,时间复杂度 O(n * log n)

思路:主要优化寻找前 k 个最高频率,不依赖排序,而是采用优先队列(堆),时间复杂度可以降为 O(n * log k)

堆(Heap)是一种特殊的完全二叉树,它满足每个节点的值都不大于(或不小于)其子节点的值的性质。根据这个性质,堆可以分为两类:

  • 最小堆(Min Heap):每个父节点的值都小于或等于其所有子节点的值。因此,树的根节点给出了全树的最小值。
  • 最大堆(Max Heap):每个父节点的值都大于或等于其所有子节点的值。因此,树的根节点给出了全树的最大值。

堆通常用于实现优先队列,因为堆能够在 O(1) 时间复杂度内访问到最小元素(在最小堆中)或最大元素(在最大堆中),并且可以在 O(log n) 时间复杂度内完成插入新元素或删除最小(或最大)元素的操作。

class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:

        # 统计元素频率
        freq_map = {}

        for num in nums:
            if num in freq_map:
                freq_map[num] += 1
            else:
                freq_map[num] = 1

        # 如何在Python中构造最小堆?
        # heapq 模块提供的堆操作是在普通的列表上进行的,所以不需要特殊的数据结构来表示堆。
        min_heap = []
        # 遍历 freq_map 字典,对于每个 (频率, 元素) 元组,使用 heapq.heappush() 将其加入到 min_heap 中。
        # 由于 Python 的堆是最小堆,元组的第一个元素(即频率)被用来确定在堆中的顺序,频率最低的元素会位于堆顶。
        for num, freq in freq_map.items():
            heapq.heappush(min_heap, (freq, num))
            # 检查堆的大小是否超过了 k
            # 使用 heapq.heappop() 函数移除堆顶元素,即频率最低的元素。
            # 这样做的目的是确保堆中始终只包含频率最高的 k 个元素。
            if len(min_heap) > k:
                heapq.heappop(min_heap)
        # 从堆中提取结果
        top_k_elements = [num for freq, num in min_heap]
        return top_k_elements
  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值