单调队列,相较于普通队列区别在于,队列中元素是单调排列的。
239. 滑动窗口最大值
该题一个直观解法是,每步移动后,对滑动窗口进行遍历,找出最大值,但该找最大值操作复杂度为O(k),会超时。因此,如何能达到O(1)复杂度找到最大值是我们的目标。
我们可以想到,对于两个相邻(只差了一个位置)的滑动窗口,它们共用着 k-1 个元素,而只有 1 个元素是变化的。我们可以根据这个特点进行优化。这可以用单调队列来求解。
解法:单调队列
单调队列,即维护队列中的队头至队尾元素单调递减。实现核心为,每次在队尾添加元素前,将所有小于该元素的元素从队尾移除,这样队头元素即为当前窗口最大值。另外需要注意的一点是,窗口是滑动的,当队头元素到达窗口的左端,即下一状态被移出窗口,这时需要将该元素从队头移除。
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
#
queue = collections.deque()
result = []
# print(queue)
for i in range(len(nums)):
if i < k-1:
while queue and queue[-1] < nums[i]:
queue.pop()
queue.append(nums[i])
else:
# 从队尾移除,保证队列内元素的单调性
while queue and queue[-1] < nums[i]:
queue.pop()
queue.append(nums[i])
# 队头元素即为当前窗口最大值
result.append(queue[0])
# 队头元素在当前窗口左边界
if nums[i-k+1] == queue[0]:
queue.popleft()
# print(queue)
return result
解法2:优先队列(最大堆)
该方法寻找最大值的时间复杂度为O(logn),具体可以参考官方解答
1122. 数组的相对排序
解法:自定义排序
可以自定义排序的比较规则,改为比较在arr2中元素对应索引大小。同时python中可以对元组进行比较,用于处理arr2中未出现元素,未出现元素按元素大小进行排序。
class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
def mycmp(x: int) -> (int, int):
return (0, rank[x]) if x in rank else (1, x)
rank = {x: i for i, x in enumerate(arr2)}
arr1.sort(key=mycmp)
return arr1
解法2:计数排序
class Solution:
def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]:
upper = max(arr1)
frequency = [0] * (upper + 1)
for x in arr1:
frequency[x] += 1
ans = list()
for x in arr2:
ans.extend([x] * frequency[x])
frequency[x] = 0
for x in range(upper + 1):
if frequency[x] > 0:
ans.extend([x] * frequency[x])
return ans