239. 滑动窗口最大值
思路
维持一个单调递减队列。左边是最大的元素,然后向右单调递减。
push
:每当新的元素从右边入队列,弹出比其小的元素pop
:滑动窗口移除最前面的元素front
:查询队伍当前最大值,也就是deque[0]
以下为动图演示:
代码
双指针,用指针来代替具体的元素。l, r
为滑动窗口的左和右
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
res = []
q = deque()
l = r = 0
while r < len(nums):
# push
while q and nums[q[-1]] <= nums[r]:
q.pop()
q.append(r)
# pop
if l > q[0]:
q.popleft()
# append the result to res, moving the l pointer only when the window is formed
if (r + 1) >= k:
res.append(nums[q[0]])
l += 1
# move the right pointer
r += 1
return res
复杂度分析
- 时间复杂度:
O(n)
- 空间复杂度:
O(k)
347.前 K 个高频元素
思路
有两种思路,但不管哪种思路,第一步都是先遍历一遍数组,做一个频率表map_
。python里面可以用Counter()
来完成。
Heap(第一种)
将(freq, key)
放进(heappush
)小顶堆(min,heap), 并将小顶堆的大小维持在k
。
代码
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
#要统计元素出现频率
map_ = {} #nums[i]:对应出现的次数
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i], 0) + 1
#对频率排序
#定义一个小顶堆,大小为k
pri_que = [] #小顶堆
#用固定大小为k的小顶堆,扫描所有频率的数值
for key, freq in map_.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
heapq.heappop(pri_que)
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
复杂度
- 时间复杂度:
O(nlogk)
- 空间复杂度:
O(n)
Heap(第二种)
将所有map_
的(key, freq)
配对,以(-freq, key)
的形式放入小顶堆。然后heappop
进行k
次即可。
代码
from collections import Counter
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
c = Counter(nums)
c = [(-v,k) for k,v in c.items()]
# heapify takes O(n) time
heapq.heapify(c)
output = []
for i in range(k):
item = heapq.heappop(c)
output.append(item[1])
return output
复杂度
- 时间复杂度:
O(klogn)
, 因为堆的大小是n
,每次heappop
用时O(logn)
- 空间复杂度:
O(n)
Bucket Sort
这是最快的一种,用到桶排序。将map_
里面的(key, val)
放进一个新数组内(称之为freq
),freq
的长度是len(nums) + 1
,这个数组相当于桶,freq
数组的index相当于nums
数组中数字可能出现的频率,freq
的数值就是一个包含nums
出现过的数字的数组。最高可能出现的频率是len(nums)
,意思是整个nums
数组都由同一个数字构成。
举个例子,如果nums = [1,1,1,2,2,100]
,那么freq
便如下图蓝色数组所示。在得到freq
之后,我们之需要倒序遍历freq
,获取k
个数字即可。
代码
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
map_ = Counter(nums)
freq = [[] for i in range(len(nums)+1)]
res = []
for key, val in map_.items():
freq[val].append(key)
for i in range(len(freq)-1, 0, -1):
for j in freq[i]:
res.append(j)
if len(res) == k:
return res
复杂度
- 时间复杂度:
O(n)
- 空间复杂度:
O(n)