📅  最后修改于: 2023-12-03 15:12:43.534000             🧑  作者: Mango
这题涉及到数据结构的知识,主要考察队列的应用。
给定一个数组和一个数k,找到数组里的数中,最大的k个数,并按照原来的相对位置返回。
例如,对于数组 [1, 23, 12, 9, 30, 2, 50] 和 k=3,返回 [23, 30, 50]
首先我们可以用堆这种数据结构来解决这个问题,时间复杂度为 O(nlogk)。
另外一种思路是利用双端队列(deque)来解决这个问题。 我们维护一个双端队列d,这个队列中要存储数组里的下标,双端队列的头部存储的是当前最大值的下标,尾部存储的是目前为止的滑动窗口内未被淘汰的下标。
当前滑动窗口为[i, j],其中 j-i+1 = k。我们可以每次把 j 加 1,并把 i 的值加 1,这样滑动窗口就向右移动一个单位。到下一个滑动窗口 [i+1, j+1] 时,我们要比较这个滑动窗口最左边的值和队头所指的值。如果队头的值下标小于 i,那么就需要把队头出队。如果队头所指的元素小于当前的左侧元素, 则需要把队头出队。
需要注意,在队列中存储的是元素的下标而不是元素值本身,即队列中的每一项应该是类似 (index, value) 的形式。另外,如果当前数组中的元素并不是数值,而是结构体或对象之类的数据类型,需要把每一个元素的数值提取出来在队列中进行比较。
以下是一个Python的实现代码片段,包含了两种方法。
from collections import deque
import heapq
def max_sliding_window(arr, k):
n = len(arr)
if n * k == 0:
return []
if k == 1:
return arr
# heap
heap = [(-arr[i], i) for i in range(k)]
heapq.heapify(heap)
res = [-heap[0][0]]
for i in range(k, n):
heapq.heappush(heap, (-arr[i], i))
while heap[0][1] <= i - k:
heapq.heappop(heap)
res.append(-heap[0][0])
return res
def max_sliding_window_deque(arr, k):
n = len(arr)
if n * k == 0:
return []
if k == 1:
return arr
# deque
q = deque()
for i in range(k):
while q and arr[i] >= arr[q[-1]]:
q.pop()
q.append(i)
res = [arr[q[0]]]
for i in range(k, n):
if q[0] == i - k:
q.popleft()
while q and arr[i] >= arr[q[-1]]:
q.pop()
q.append(i)
res.append(arr[q[0]])
return res
以上是使用两种不同的解法来解决本题的代码实现。堆的效率需要更高,但需要使用额外的空间作为堆的辅助空间。使用双端队列可以避免使用额外的空间,但是需要更多的代码来实现。
最好的做法应该是遍历数组时,把最大值保存在变量中,同时记录下它所处的位置。再利用一个集合(set)来记录内部最大值的数量,如果当前数字比最大值还大,那么就把全部集合清空并记录值和位置。这种做法的时间复杂度为$O(n)$,空间复杂度为$O(k)$。
##参考链接
[1] https://leetcode.com/problems/sliding-window-maximum/
[2] https://leetcode.com/articles/sliding-window-maximum/
[3] https://www.geeksforgeeks.org/sliding-window-maximum-maximum-of-all-subarrays-of-size-k/
[4] https://blog.csdn.net/huanghanqian/article/details/88938612