📅  最后修改于: 2023-12-03 15:42:19.283000             🧑  作者: Mango
有一个长度为n(n<=10000)的整形数组a和一个大小为k(k<=n)的滑动窗口,从数组的最左端移动到最右端,每次只移动一个位置。例如,当n=6且k=4时,滑动窗口如下:
[1 3 -1 -3 5 3 6 7],k=4的滑动窗口的最大值是3,3,5,5,6,7
请实现一个函数来找到在滑动窗口中的每个位置的最大值。
函数原型:void MaxValue(int a[], int n, int b[], int k)
其中a为整形数组,n为其大小,b为存储最大值的数组,其大小为k。
例如,当a = [1, 3, -1, -3, 5, 3, 6, 7], n = 8时,当k = 4时,函数应返回值为b = [3, 3, 5, 5, 6, 7]。
本题可以使用单调队列来解决。具体来说,我们维护一个单调递减的队列,队首元素即为当前的滑动窗口的最大值。当我们移动窗口时,需要判断当前的队列是否已经过期,即队列中存储的元素是否都已经在当前的滑动窗口中,如果队首元素不在滑动窗口中,则需要将其弹出。然后,我们将新的元素加入到队列的末尾,并将队列中比其小的元素都弹出,因为它们在当前滑动窗口中一定不可能是最大值。
void MaxValue(int a[], int n, int b[], int k) {
deque<int> q; // 用deque来实现单调队列,队列中存储的是数组下标
for (int i = 0; i < n; i++) {
// 处理队首元素过期的情况
if (!q.empty() && q.front() <= i - k) {
q.pop_front();
}
// 将队列中比a[i]小的元素全部弹出
while (!q.empty() && a[q.back()] < a[i]) {
q.pop_back();
}
// 将a[i]加入队列尾部
q.push_back(i);
// 记录最大值
if (i >= k - 1) {
b[i - k + 1] = a[q.front()];
}
}
}
该算法的时间复杂度为$O(n)$,因为每个元素最多进出队列一次,且队列中元素个数不超过n。