239、滑动窗口最大值
from collections import deque
class Solution(object):
def __init__(self):
self.q = deque()
def pop_value(self, val):
if self.q and self.q[0] == val:
self.q.popleft()
def push(self, val):
while self.q and val > self.q[-1]:
self.q.pop()
self.q.append(val)
def get_value(self):
return self.q[0]
def maxSlidingWindow(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
res = []
for i in range(k):
self.push(nums[i])
for j in range(len(nums)-k+1):
res.append(self.get_value())
if j+k >= len(nums):
break
self.pop_value(nums[j])
self.push(nums[j+k])
return res
需构造一个单调队列,其中push方法需要从尾端比较和pop元素,要注意不能从头端,队列里不一定要维持K个元素,只要保证最大元素位于头端,遍历时可拿到就行,移除头部元素时要判断是否是当前要移除的元素
347、前K个高频元素
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
from collections import defaultdict
hash_map = defaultdict(int)
for i, c in enumerate(nums):
hash_map[c] += 1
return sorted(set(nums), reverse=True, key=lambda x: hash_map[x])[:k]
用sorted直接排序,时间复杂度nlogn
进阶方法(优先级队列暨小顶堆法):
class Solution(object):
def topKFrequent(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
hash_map = {}
for c in nums:
hash_map[c] = hash_map.get(c, 0) + 1
import heapq
heap = []
for key, val in hash_map.items():
heapq.heappush(heap, (val, key))
if len(heap) > k:
heapq.heappop(heap)
res = [0] * k
for i in range(k-1, -1, -1):
res[i] = heapq.heappop(heap)[1]
return res
解决该问题分三个步骤,对元素出现频率进行统计,对统计好的频率排序,输出前K个高频元素
主要是对频率排序,构造一个长度为K的优先级队列(小顶堆),对map里的pair进行排序,因为小顶堆不断弹出堆顶的最小优先级的pair,所以最后留下来的是前K个高频元素,最后再倒叙输出即可,不用大顶堆是因为需要构造map长度也就是N的堆,而小顶堆只需要维护K个键值对即可
总结:
栈和 队列都是属于容器适配器,根据其容器底层实现方式不同,具有不同的特性,栈是属于后入先出,特别适合于解决匹配类问题,涉及到的经典题目有括号匹配,相邻字符串去除重复项,逆波兰表达式等,队列涉及到的经典题目有滑动窗口最大值,前K个高频元素等,分别用到了单调队列以及优先级队列,python语言中栈不是内置结构,可以用列表,deque等实现,队列有双端队列deque,以及queue模块包含的各种队列,还有优先级队列(堆排序)可以用heapq实现