思路:单调队列
具体思路: 维护一个从队头到队尾单调递减的队列。
优化: 队列直接存下标,就不存元素值了。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
deque<int> dq;
vector<int> ans;
for (int i = 0; i < k; ++i) {
while (!dq.empty() && nums[dq.back()] < nums[i]) dq.pop_back();
dq.push_back(i);
}
if (dp.size()) ans.push_back(nums[dq.front()]); //加判断
for (int i = k; i < n; ++i) {
while (!dq.empty() && nums[dq.back()] < nums[i]) dq.pop_back();
dq.push_back(i);
while (dq.front() < i - k + 1) dq.pop_front();
ans.push_back(nums[dq.front()]);
}
return ans;
}
};
代码:用front() 和back()
易错点:考虑数组为空的情况。
思路二:优先队列 O(nlogn) 复杂度高
难点: 从堆中删除指定元素(窗口滑动后左边的元素)不可能实现,怎么处理?
解决方案 那就不删除呗,每次得到最大元素的时候,判断堆顶元素是否在滑动窗口中,如果不在一直删除堆顶元素直到堆顶元素是滑动窗口内的元素
难点: 那么怎么判断栈顶元素是否属于窗口内元素这个集合呢?
解决方案: 堆中元素的类型为pair<int, int>,first存nums[index],second存index,每次对堆顶元素的second与窗口的左边界进行对比
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
priority_queue<pair<int, int>> pq;
vector<int> ans;
for (int i = 0; i < k; ++i) {
pq.push({nums[i], i});
}
ans.push_back(pq.top().first);
for (int i = k; i < n; ++i) {
pq.push({nums[i], i});
while (pq.top().second < i - k + 1) pq.pop();
ans.push_back(pq.top().first);
}
return ans;
}
};
思路三:set O(nlogk) 复杂度较高
注意: 数组中可能会存在重复元素,所以不能用set,改成multiset
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
int n = nums.size();
multiset<int, greater<int>> st;
vector<int> ans;
for (int i = 0; i < k; ++i) {
st.insert(nums[i]);
}
if (st.size()) ans.push_back(*st.begin());
for (int i = k; i < n; ++i) {
st.erase(st.find(nums[i - k]));
st.insert(nums[i]);
ans.push_back(*st.begin());
}
return ans;
}
};
易错点:
multiset 可能有重复元素,删除一个元素时会都删掉:mst.erase(st.find(nums[i - k]));