这个题目暴力法的思路特别简单,效率也最差O(nk)。
倒数第二个测试用例超时了。。。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
for(auto left = nums.begin(); left <= nums.end()-k; ++left){
auto max = *max_element(left, left+k);
res.push_back(max);
}
return res;
}
};
这题标题叫做滑动窗口最大值,可是我用滑动窗口的思路想了好久愣是不知道怎么实现线性时间复杂度。
分析一下,首先窗口滑动的O(n)是不可避免的,要优化代码的话只能从最大值获取这一块入手,我们知道最大堆(优先队列)能够实现O(1)时间取出最大值,但是窗口滑动时需要进行元素删除(O(k))和插入(O(logk)),所以复杂度还是O(nk)。
逆向思维反推一下,要求线性时间复杂度,而窗口滑动复杂度就是O(n),所以就需要在O(1)时间内获取当前窗口的最大值。想要达到O(1),那就只能使用单调队列的思路了。维护一个单调队列,总是让最大值位于队列末尾,那么就可以o(1)复杂度获取最大值。
所以分析一下,窗口滑动的时候,我们需要进行单调队列内元素的更新:
- 如果队列头部的元素不再位于当前窗口,就应该删除。
- 如果窗口内新增的元素大于队列尾部的元素,就可以进行添加。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
if(k == 1) return vector<int>(nums.begin(), nums.end()-k+1);
deque<int> q;
vector<int> res;
for(int i = 0; i < n; ++i){//队首最大,队尾最小
//比当前nums[i]还小的元素,就没必要存在了(最大值不可能是它)
while(!q.empty() && nums[q.back()] < nums[i]) q.pop_back();
while(!q.empty() && i-q.front() >= k) q.pop_front();
q.push_back(i);//存储的是下标
if(i >= k-1) res.push_back(nums[q.front()]);
}
return res;
}
};