【代码随想录】d13-栈与队列-part03-python

1.239. 滑动窗口最大值

1.1题目及讲解

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html

1.2代码实现

方法一:暴力解法,超时

nums = [1,3,-1,-3,5,3,6,7]
k = 3

def fun():
    arr = []
    n = k
    for i in range(len(nums)-k+1):
        arr.append(max(nums[i:n]))
        n += 1
    return arr

print(fun())

方法二:单调队列

import collections
class MyQueue:
    def __init__(self):
        self.queue = collections.deque()

    def push(self,x):
        # 当队列不为空,同时新增的值大于前面的值时(不一定是最前端的最大值值),就持续把小于当前值的删掉,删完之后把新增的值加进来
        # 这里有两种情况,一种是最大值大于新增值,那么就会形成单调队列(前面的删除了一部分)
        # 最大值小于新增值,那么最后队列内就只会有新增值(前面的全部删除了)
        while self.queue and x > self.queue[-1]:
            self.queue.pop()
        self.queue.append(x)

    def pop(self,x):
        # 从前端删除
        if self.queue and x ==self.queue[0]:
            self.queue.popleft()

    def get_max_value(self):
        return self.queue[0]


nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
que = MyQueue()
res = []
for i in range(k):
    que.push(nums[i])
res.append(que.get_max_value())
for i in range(k,len(nums)):
    que.push(nums[i])
    que.pop(nums[i-k])
    res.append(que.get_max_value())
print(res)

分析:
1.为什么要保留pop方法?

  • 如果nums=[1,-1,-1,-1],k=1,走到下标1时,应该只保留-1,但是不调用pop时,前面的1就删不到

2.双端队列,最右边(前端)始终放最大值,当新进来的值大于前面的值,那么就从最后面(后端)开始删除,一直删到队列单调递增

2.347.前 K 个高频元素

2.1题目及讲解

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

题目链接/文章讲解/视频讲解:https://programmercarl.com/0347.%E5%89%8DK%E4%B8%AA%E9%AB%98%E9%A2%91%E5%85%83%E7%B4%A0.html

2.2代码实现

import heapq
nums = [1,1,1,2,2,3]
k=2
def fun():
    dic = {}
    lis = []
    # 第一步:获取所有元素的出现频率
    for i in nums:
        dic[i] = dic.get(i,0)+1
    # 第二步:通过小顶堆获取出现频率最高的元素
    for e,times in dic.items():
        # 遍历字典,把每一组数据推入lis中
        heapq.heappush(lis,(times,e))  # 元素e和times频率,在放入lis时位置交换了,主要是因为要根据频率排序
        # 只需要维护k组数据,超过k个的直接删除,这里pop是从最小的开始删除
        if len(lis) > k:
            heapq.heappop(lis)
    # 第三步:由于lis的顺序是从小到大(map结构),题目要求只返回元素,所以结果需要先整理再返回
    return [i[1] for i in lis[::-1]]

print(fun())

记录代码随想录的思路:
这道题目主要涉及到如下三块内容:

  • 要统计元素出现频率
  • 对频率排序
  • 找出前K个高频元素

首先统计元素出现的频率,这一类的问题可以使用map来进行统计。
然后是对频率进行排序,这里我们可以使用一种 容器适配器就是优先级队列。

什么是优先级队列呢?

  • 其实就是一个披着队列外衣的堆,因为优先级队列对外接口只是从队头取元素,从队尾添加元素,再无其他取元素的方式,看起来就是一个队列。

而且优先级队列内部元素是自动依照元素的权值排列。那么它是如何有序排列的呢?

缺省情况下priority_queue利用max-heap(大顶堆)完成对元素的排序,这个大顶堆是以vector为表现形式的complete binary tree(完全二叉树)。

什么是堆呢?

  • 堆是一棵完全二叉树,树中每个结点的值都不小于(或不大于)其左右孩子的值。 如果父亲结点是大于等于左右孩子就是大顶堆,小于等于左右孩子就是小顶堆。

3.Python中的heapq模块

3.1 heapq模块简介

heapq 是 Python 标准库中的模块,用于实现堆数据结构(heap)的操作。堆是一种特殊的二叉树结构,具有以下特点:

  1. 堆是一个完全二叉树,即除了最底层,其他层都是满的,并且最底层从左到右填充。
  2. 堆中的每个节点的值都必须满足堆属性(heap property),即父节点的值小于或等于其子节点的值(对于最小堆)或大于或等于其子节点的值(对于最大堆)。

3.2 heapq模块函数

Python 的 heapq 模块提供了一些函数,可以对列表(可看作是一个完全二叉树)进行堆操作,包括插入元素、删除最小/最大元素等。以下是 heapq 模块中常用的一些函数:

  • heappush(heap, item):将元素 item 添加到堆 heap 中。
  • heappop(heap):从堆 heap 中弹出并返回最小/最大元素。
  • heapify(heap):将列表 heap 转换为一个堆。
  • heapreplace(heap, item):将最小/最大元素弹出并返回,然后将新元素 item 推入堆 heap。
  • heappushpop(heap, item):将元素 item 推入堆 heap,然后从堆中弹出并返回最小/最大元素。

可以使用 import heapq 语句导入 heapq 模块,然后通过调用上述函数来进行堆操作。通常情况下,要使用堆进行排序,首先使用 heapify() 将列表转换为堆,然后使用 heappop() 或其他函数来获取排序后的元素。
示例:

import heapq
# 创建一个空堆
heap = []

# 添加元素到堆中
heapq.heappush(heap, 4)
heapq.heappush(heap, 2)
heapq.heappush(heap, 8)
heapq.heappush(heap, 1)

# 弹出并打印堆中的最小元素
print(heapq.heappop(heap))  # 输出: 1

# 将列表转换为堆
list1 = [6, 3, 9, 5]
heapq.heapify(list1)
print(list1)  # 输出: [3, 5, 9, 6]

通过使用 heapq 模块,可以在 Python 中方便地实现堆数据结构的操作。

你可能感兴趣的:(python,leetcode)