题目链接
题目描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例
示例1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值
[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
提示
1 <= nums.length <= 10-10 <= nums[i] <= 10-
思路
思路1:大根堆(优先队列)
要求最大值,我们可以考虑使用大根堆。
初始时,将k个元素放入堆中,然后移动窗口,将新元素放入堆中,但此时堆顶元素可能已经不在窗口中了,因此我们需要判断堆顶元素是否在窗口中。
解决方法是,堆元素为一个二元数组pair<int, int> (num, index),每次判断堆顶元素即可。思路2:单调队列
类似于单调栈,我们设想一个单调队列
MonotoneQueue,这个队列里的元素是单调的(本题为单调减)。它有如下基本操作: void pop(num)如果队首元素等于num,则弹出队首元素,否则不进行任何操作。void push(num)如num大于队尾元素,那么弹出队尾元素继续比较,直到num不大于队尾元素,此操作保证了单调性。int getMax()取队首元素,即最大值。
我们使用上述的单调队列解决本题:在窗口移动的过程中,加入新的元素,并判断被移出窗口的元素是否要从队列中移除,取最大值就是此时窗口的最大值。
思路3:分治+DP
将数组 nums 按 k 个一组分组,最后一组可能不足 k 个。那么窗口 num[i] 到 num[i + k - 1] 中最大值有两种情况:
i是k的倍数,那么窗口num[i]到num[i + k - 1]恰好为一个分组。i不是k的倍数,设j为k的倍数,且i < j <= i + k - 1,窗口num[i]到num[i + k - 1]会跨越num[i]到num[j - 1]和num[j]到num[i + k - 1]两个分组,因此我们要求前者的后缀和后者的前缀的最大值。
题解
思路1:大根堆(优先队列)
class Solution {public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {priority_queue<pair<int, int>> maxHeap;for (int i = 0; i < k; ++i) {maxHeap.emplace(nums[i], i);}vector<int> ans = {maxHeap.top().first};for (int i = k; i < (int)nums.size(); ++i) {maxHeap.emplace(nums[i], i);while (maxHeap.top().second <= i - k) {maxHeap.pop();}ans.emplace_back(maxHeap.top().first);}return ans;}};
思路2:单调队列
class MonotoneQueue {private:deque<int> _queue;public:MonotoneQueue(){};~MonotoneQueue(){};void pop(int value) {if (!_queue.empty() && _queue.front() == value) {_queue.pop_front();}}void push(int value) {while (!_queue.empty() && _queue.back() < value) {_queue.pop_back();}_queue.push_back(value);}int getMax() {return _queue.front();}};class Solution {public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {MonotoneQueue monotoneQueue;for (int i = 0; i < k; ++i) {monotoneQueue.push(nums[i]);}vector<int> ans = {monotoneQueue.getMax()};for (int i = k; i < (int)nums.size(); ++i) {monotoneQueue.pop(nums[i - k]);monotoneQueue.push(nums[i]);ans.emplace_back(monotoneQueue.getMax());}return ans;}};
思路3:分治+DP
class Solution {public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {int n = nums.size();vector<int> prefixMax(n), suffixMax(n);vector<int> ans;prefixMax[0] = nums[0];for (int i = 1; i < n; ++i) {prefixMax[i] = 0 == i % k ? nums[i] : max(prefixMax[i - 1], nums[i]);}suffixMax[n - 1] = nums[n - 1];for (int i = n - 2; i >= 0; --i) {suffixMax[i] = 0 == (i + 1) % k ? nums[i] : max(suffixMax[i + 1], nums[i]);}for (int i = 0; i <= n - k; ++i) {ans.emplace_back(max(prefixMax[i + k - 1], suffixMax[i]));}return ans;}};
