📜  门| GATE-IT-2004 |第 44 题(1)

📅  最后修改于: 2023-12-03 15:42:19.283000             🧑  作者: Mango

门(GATE)-IT-2004 第 44 题

题目描述

有一个长度为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。