今天主要进行队列的应用训练
239. 滑动窗口最大值
LeetCode - The World's Leading Online Programming Learning Platform
思路:本题如果采用简单的滑动窗口做法, 每次在滑动窗口中循环找到最大值, 可以实现 O(m*n) 负责度的算法。 如果要提升代码的速度, 需要考虑如何记录上一个滑动窗口的最大值已经最大值的位置。 这道题可以采用 优先级对列来处理, 但是这道题采用的是滑动窗口, 优先级队列每次弹出的是最大值,而不是特定位置的值。所以不容易处理。
这道题其实需要注意特定位置的值, 例如队列 [1, 3, -1, 2,1] k=3 我们只需要知道什么时候3 被移除了滑动窗口, 或者移除前有没有比3 还大的元素。 所以可以想到通过 deque 来记录当前滑动窗口内随着下标变高的递减序列。 例如第一个窗口记录 [3, -1], 到了第二个窗口记录 [3, 2]. 实现起来就是, 当滑动窗口移动一次, 如果移出的元素 等于 deque 的 第一位,那么把这个元素从deque 中 pop 出来, 否则不做处理 (例如第一次移动, 1 被移动出来)。 如果移动滑动窗口,新的元素被涵盖进来,比较新元素和 deque 末尾的大小, 如果大于末尾元素, pop 出这个元素, 直到 deque 空了, 或着末尾元素小于等于当前元素。 然后当前元素 push 进去。
from collections import deque
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
q = deque([nums[0]])
for i in range(1, k):
while len(q)>0 and nums[i] > q[-1]:
q.pop()
q.append(nums[i])
ans = [q[0]]
for i in range(k, len(nums)):
remove_num = nums[i-k]
put_num = nums[i]
if remove_num == q[0]:
q.popleft()
while len(q)>0 and put_num > q[-1]:
q.pop()
q.append(put_num)
ans.append(q[0])
return ans
347.前 K 个高频元素
LeetCode - The World's Leading Online Programming Learning Platform
思路:先 count 每个元素出现的次数。然后如果直接排序的话 时间复杂度 O(n*logn). 本题可以采用小顶堆。 count 完成之后把 (count, num)这样的set 放入小顶堆中, 如果小顶堆长度超出K 了, 就 pop 出来一个最小的值。 最后剩的K个元素就是要找的前 K个高频元素。
import heapq
from collections import Counter
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
c = Counter(nums)
prio_q = [] # 小顶堆
for num, freq in c.items():
heapq.heappush(prio_q, (freq, num))
if len(prio_q) > k:
heapq.heappop(prio_q)
ans = []
while len(prio_q) > 0:
_tmp = heapq.heappop(prio_q)
ans.append(_tmp[1])
return ans