You are given an array of integers nums
, there is a sliding window of size k
which is moving from the very left of the array to the very right. You can only see the k
numbers in the window. Each time the sliding window moves right by one position.
Return the max sliding window.
Example 1:
Input: nums = [1,3,-1,-3,5,3,6,7], k = 3 Output: [3,3,5,5,6,7] Explanation: Window position Max --------------- ----- [1 3 -1] -3 5 3 6 7 3 1 [3 -1 -3] 5 3 6 7 3 1 3 [-1 -3 5] 3 6 7 5 1 3 -1 [-3 5 3] 6 7 5 1 3 -1 -3 [5 3 6] 7 6 1 3 -1 -3 5 [3 6 7] 7
思路:维护一个长度为当前window长度的单调队列,每次output这个单调队列里最大的值就是所求的值。window每向右挪动1位,push这个值到单调队列里,pop出比这个值小的已在队列里的值,因为这些值永远不会成为最大值了。但是注意当队列最左的元素从window中挪出后,就要从单调队列里也挪出对应的值。以下的第一种方法在挪出左边的元素时,是通过比较实际数值来判断单调队列最左(最大)的值是否是队列最左的值,继而判断队列中是否要挪出。第二种写法里,单调队列中维护的是元素的序号而不是值本身,这样在判断是否需要挪出单调队列中最左(最大)的元素时,用if i-d[0] >= k: d.popleft()即可,感觉更加优雅。
from collections import deque
class MyQueue: # Monotonic queue # from large to small
def __init__(self):
self.queue = deque() #Using a list would be inefficient over time, so we are using a queue here for bidirectional functionality.
def pop(self, value):
if self.queue and value ==self.queue[0]:
self.queue.popleft()
# Push a new value into the queue and remove items smaller than it for a sorted queue
def push(self, value):
while self.queue and value > self.queue[-1]:
self.queue.pop()
self.queue.append(value)
# check the largest value in the queue
def front(self):
return self.queue[0]
def length(self):
return len(self.queue)
# 写法1: 对比值来判断是否pop最左的元素
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
myque = MyQueue()
result = []
for i in range(k):
myque.push(nums[i])
result.append(myque.front())
for i in range(k, len(nums)):
if myque.length() < k:
myque.push(nums[i])
else:
myque.pop(nums[i-k])
myque.push(nums[i])
result.append(myque.front())
return result
# 写法二:存入单调序列的本就是元素的位置序号
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
d = deque()
n = len(nums)
res = []
for i in range(k):
while d and nums[d[-1]] <= nums[i]:
d.pop()
d.append(i)
res.append(nums[d[0]])
for i in range(k,n):
if i-d[0] >= k :
d.popleft()
while d and nums[d[-1]] <= nums[i]:
d.pop()
d.append(i)
res.append(nums[d[0]])
return res
时间复杂度:O(n)
Given an integer array nums
and an integer k
, return the k
most frequent elements. You may return the answer in any order.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2 Output: [1,2]
思路:统计出每类元素的个数后,进行排序。也可以用快排,但没必要对整个序列排序,这里维护一个长度为k的排序就可以了。用min-heap,保证最top上就是最小的值,然后不断pop频率最小的值,直到最后留在heap里的只有k个值,这k个才是出现频率最高的k个值,这时候再对这k个排序即可。
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
# count the occurance of each value
map_ = {}
for i in range(len(nums)):
map_[nums[i]] = map_.get(nums[i], 0) + 1
# Sort the heap in size k
# The smallest value is on the top
pri_que = []
for key,freq in map_.items():
heapq.heappush(pri_que, (freq, key))
if len(pri_que) > k: # If the size of the heap is larger than k, pop the one with smallest frequency
heapq.heappop(pri_que)
# Find the top k highest item. The smallest is popped first so the order is revered for the output.
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
时间复杂度 O(nlogk)。因为 heapq.heappop(pri_que), heapq.heappush(pri_que, (freq, key)) 的复杂度是O(logk),最多有n个元素要被push,复杂度就为O(nlogk)了。len(pri_que)的复杂度是O(1)。