python coding with ChatGPT 打卡第11天| 栈和队列:滑动窗口最大值、前k个高频元素

本文详细介绍了如何使用单调队列解决滑动窗口最大值问题,以及利用优先级队列(大顶堆或小顶堆)优化时间复杂度来找出前k个高频元素。通过暴力解法和无库函数实现进行对比分析。
摘要由CSDN通过智能技术生成

相关推荐
python coding with ChatGPT 打卡第9天| 栈和队列:基础知识
python coding with ChatGPT 打卡第10天| 栈和队列:有效的括号 逆波兰表达式求值

滑动窗口最大值

在这里插入图片描述

Key Points

单调队列的经典题目

相关题目

239. 滑动窗口最大值

视频讲解

单调队列正式登场

重点分析

暴力解法:

def maxSlidingWindow(nums, k):
    i=0
    j=i+k
    res = []
    while j <= len(nums):
        res.append(max(nums[i:j]))
        i += 1
        j += 1
    return res

from collections import deque

在这里插入图片描述

单调队列:
在这里插入图片描述

解释:第一个窗口,3既比1大,又比1活得久,所以1就没有用了。
(对于某一个窗口,更靠右且更大的元素,更可能成为最大值的候选值)
from collections import deque

def maxSlidingWindow(nums, k):
    # 如果数组为空或者k为0,则返回空列表
    if not nums or k == 0:
        return []

    # 初始化双端队列和结果列表
    deq = deque()
    result = []

    for i in range(len(nums)):
        # 当队列头部元素索引不在滑动窗口内时,将其从队列中移除
        if deq and deq[0] < i - k + 1:
            deq.popleft()

        # 从队列尾部移除所有比当前元素小的元素索引
        while deq and nums[i] > nums[deq[-1]]:
            deq.pop()

        # 将当前元素的索引添加到队列尾部
        deq.append(i)

        # 当窗口形成时,队列头部元素即为窗口内的最大值
        if i >= k - 1:
            result.append(nums[deq[0]])

    return result

在这里插入图片描述

如果不能使用库函数,如 collections.deque,仍然可以使用列表来模拟双端队列的功能。我们将手动实现添加和删除操作来维护窗口内元素的索引。以下是不使用库函数的实现方法:

def maxSlidingWindow(nums, k):
    # 如果数组为空或者k为0,则返回空列表
    if not nums or k == 0:
        return []

    # 初始化结果列表和模拟双端队列的列表
    result = []
    deq = []

    for i in range(len(nums)):
        # 当队列头部元素索引不在滑动窗口内时,将其从队列中移除
        if deq and deq[0] < i - k + 1:
            deq.pop(0)

        # 从队列尾部移除所有比当前元素小的元素索引
        while deq and nums[i] > nums[deq[-1]]:
            deq.pop()

        # 将当前元素的索引添加到队列尾部
        deq.append(i)

        # 当窗口形成时,队列头部元素即为窗口内的最大值
        if i >= k - 1:
            result.append(nums[deq[0]])

    return result

在这里插入图片描述

前k个高频元素

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

Key Points

时间复杂度的优化:

无需全部排序(nlogn),秩序维护k个有序集合即可

相关题目

347. 前k个高频元素

视频讲解

优先级队列正式登场!大顶堆小顶堆

重点分析

暴力解法:

def topKFrequent(nums, k):
    nums_count = {}
    for x in nums:
       nums_count[x] = nums_count.get(x, 0) + 1
    nums_sort = sorted(nums_count.items(), key=lambda x:x[1], reverse=True)
    res = []
    for i in range(k):
        res.append(nums_sort[i][0])
    return res

在这里插入图片描述

import heapq

def topKFrequent(nums, k):
    # 构建频率哈希表
    nums_count = {}
    for num in nums:
        nums_count[num] = nums_count.get(num, 0) + 1

    # 构建最小堆,堆的大小为 k
    # 堆中的元素是一个元组,结构为 (频率, 元素)
    min_heap = []
    for num, freq in nums_count.items():
        heapq.heappush(min_heap, (freq, num))
        if len(min_heap) > k:
            heapq.heappop(min_heap)

    # 从最小堆中提取元素,构建结果列表
    result = [heapq.heappop(min_heap)[1] for _ in range(k)]
    return result[::-1]  # 可能需要反转列表以得到正确的顺序

在这里插入图片描述

如果不能用库函数呢?

如果不能使用库函数,我们可以手动实现一个最小堆。最小堆是一种常见的数据结构,用于高效地管理优先级队列。以下是不使用库函数实现的代码:

def topKFrequent(nums, k):
    # 构建频率哈希表
    nums_count = {}
    for num in nums:
        nums_count[num] = nums_count.get(num, 0) + 1

    # 手动实现最小堆
    def heapify(arr, n, i):
        smallest = i
        l = 2 * i + 1
        r = 2 * i + 2

        if l < n and arr[l][0] < arr[smallest][0]:
            smallest = l
        if r < n and arr[r][0] < arr[smallest][0]:
            smallest = r

        if smallest != i:
            arr[i], arr[smallest] = arr[smallest], arr[i]
            heapify(arr, n, smallest)

    def insertHeap(arr, num):
        size = len(arr)
        if size < k:
            arr.append(num)
            size += 1
        elif num[0] > arr[0][0]:
            arr[0] = num
            heapify(arr, size, 0)

    # 构建最小堆
    min_heap = []
    for num, freq in nums_count.items():
        insertHeap(min_heap, (freq, num))

    # 从最小堆中提取元素,构建结果列表
    result = [item[1] for item in min_heap]
    return result

# 测试函数
print(topKFrequent([1, 1, 1, 2, 2, 3], 2))  # 输出应为 [1, 2]

在这里插入图片描述

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值