剑指 Offer 59 - I. 滑动窗口的最大值
个人思路
题意
思路
滑动窗口的原理符合队列先进先出的性质,因此要考虑使用队列
关键要考虑一个问题
如果pop出当前最大值,要如何再次寻找滑动窗口中的最大值
暴力模拟
- deque模拟滑动窗口
- 模拟第一次滑动窗口,使用temp表示当前最大值
- 如果出队元素是当前最大值,则重新遍历一遍滑动窗口,重新选出当前最大值(由于deque可以用下标访问,因此选用deque)
双端队列
- deque存放元素的索引,且队首元素为滑动窗口中的最大值
- 如果当前元素有可能成为最大元素,删除队尾元素(因此需要用deque从队首pop_back),将当前元素放在队首
- 如果队首元素超出窗口的大小范围,需要删除队首元素,对队列进行出队操作
注意
- 数组为空
- 滑动窗口为1,即输出数组中所有元素
个人思路代码
暴力模拟
class Solution {
public:
const int inf = -0x3fffffff;
vector<int> ans;
int temp;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(nums.size() == 0){
return ans;
}
if(k == 1){
for(int i = 0; i < nums.size(); ++i){
ans.push_back(nums[i]);
}
return ans;
}
deque<int> dq;
for(int i = 0; i < k; ++i){//第一个滑动窗口
if(nums[i] > temp){
temp = nums[i];
}
dq.push_back(nums[i]);
}
ans.push_back(temp);
for(int i = k; i < nums.size(); ++i){
if(nums[i] > temp){
temp = nums[i];
}
int head = dq.front();
dq.pop_front();
dq.push_back(nums[i]);
if(head == temp){
temp = inf;
for(int j = 0; j < dq.size(); ++j){
if(dq[j] > temp){
temp = dq[j];
}
}
}
ans.push_back(temp);
}
return ans;
}
};
双端队列
class Solution {
public:
vector<int> ans;
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if(nums.size() == 0){
return ans;
}
deque<int> index;//存放的是索引,队首元素为当前最大元素
for(int i = 0; i < k; ++i){//第一个滑动窗口
while(!index.empty() && nums[i] >= nums[index.back()]){//队列不空,且当前元素大于队尾元素
index.pop_back();//清空后面的元素,让最大元素放在队首
}
index.push_back(i);
}
for(int i = k; i < nums.size(); ++i){
ans.push_back(nums[index.front()]);//队首元素存入ans
while(!index.empty() && nums[i] >= nums[index.back()]){//队列不空,且当前元素大于队尾元素
index.pop_back();//清空后面的元素(正因为如此,才需要双端队列),让最大元素放在队首
}
if(!index.empty() && index.front() < i - k + 1){//判断队首元素是否超出窗口范围
index.pop_front();//清除超出范围的元素
}
index.push_back(i);
}
ans.push_back(nums[index.front()]);
return ans;
}
};