C--3-进阶算法(2)-滑动窗口/单调栈
序号 | 滑动窗口类题目 |
---|---|
1 | 滑动窗口的最大值 |
2 | 实现最大值队列 |
3 | 和为s的连续正数序列 |
4 | 最长不含重复字符的子字符串(滑动窗口) |
题目1 滑动窗口的最大值
标准的滑动窗口解法!!!!!
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
// 定义一个双端队列
deque<int> window;
vector<int> ans;
if (nums.empty())
{
return ans;
}
for ( int i = 0 ; i < nums.size(); i++ ) // 对每个位置进行入窗口的操作
{
// r 右移策略
while ( !window.empty() && nums[window.back()] <= nums[i] )
{
window.pop_back();
}
window.push_back( i );
// 每次检查窗口最前面的元素是否过期
if ( window.front() <= i - k )
{
window.pop_front();
}
// 窗口大小存储元素
if ( i >= k-1 )
{
ans.push_back( nums[window.front()] );
}
}
return ans;
}
};
- 自己的做法
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
// 定义一个双端队列
deque<int> window;
vector<int> ans;
if (nums.empty())
{
return ans;
}
int cur_max = nums[0];
// 把初始窗口填上, 求得当前窗口最值, 注册
int m = k <= ( nums.size()) ? k :nums.size();
for(int i = 0 ; i < m ; i ++)
{
window.push_back(nums[i]);
cur_max = max( cur_max , window.back());
}
ans.push_back(cur_max);
// 窗口大小要是比数组size大,就不用滑动了
if ( k >= nums.size())
{
return ans;
}
// 从 k 位置开始滑动,前端出一个,后端进一个
for (int i = k; i < nums.size() ; i ++ )
{
int out = window.front();
window.pop_front();
window.push_back(nums[i]);
// ①如果 out 的 数字 不是当前最大值
// 只需要用 cur_max 和 in 的值比较就可以确定新的最大值
if ( out != cur_max)
{
cur_max = (cur_max > nums[i]) ? cur_max : nums[i];
}
// ②如果 out 的 数字 刚好是当前最大值
// 分为两种情况
// A--> in 的值比 out 的值 大 或相等
// B--> in 的值比 out 小 , 那就只能在队列里遍历求新的最大值了
else if (out == cur_max)
{
if (nums[i] >= out)
{
cur_max = nums[i];
}else{
cur_max = window.front();
for (int j = 0 ; j < window.size(); j ++)
{
cur_max = max(cur_max, window[j]);
}
}
}
ans.push_back(cur_max);
}
return ans;
}
};
题目2 - II. 队列的最大值
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
示例 1:
输入:
["MaxQueue","push_back","push_back","max_value","pop_front","max_value"]
[[],[1],[2],[],[],[]]
输出: [null,null,null,2,1,2]
示例 2:
输入:
["MaxQueue","pop_front","max_value"]
[[],[],[]]
输出: [null,-1,-1]
class MaxQueue {
public:
deque<int> window; // 维持最大值的窗口
deque<int> queue_; // 维持基本元素的队列
MaxQueue() {
}
// 直接返回最大值窗口的front()
int max_value() {
if ( window.empty() ){
return -1 ;
}else{
return window.front();
}
}
// 从后面插入-> 修改基本队列 和 最大值窗口
void push_back( int value ) {
queue_.push_back(value);
while ( ! window.empty() && window.back() <= value)
{
window.pop_back();
}
window.push_back(value);
}
// 从前端弹出-->
int pop_front() {
if ( queue_.empty() )
return -1;
int ans = queue_.front();
queue_.pop_front();
// ①如果要弹出的元素刚好等于 --> window.pop_front()
// ②如果不等于 window,front() ,说明在这个元素插入之后,有比他大的元素进了window ,所以window里不可能有它,不用管了
if ( ans == window.front() )
{
window.pop_front();
}
return ans;
}
};
/**
* Your MaxQueue object will be instantiated and called as such:
* MaxQueue* obj = new MaxQueue();
* int param_1 = obj->max_value();
* obj->push_back(value);
* int param_3 = obj->pop_front();
*/
题目3 和为s的连续正数序列(滑动窗口)
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
class Solution {
public:
vector<vector<int>> findContinuousSequence( int target ) {
vector<vector<int>> ans;
deque<int> window;
int num = target >> 1 ;
int sum = 0 ;
vector<int> tmp;
// 遍历到中位数的下一位就可以了, 进队列,
for ( int i = 1 ; i <= num+1 ; i++)
{
window.push_back(i);
sum = sum + i ;
// 只要是当前队列和 大于target , 就从前面 pop
while( sum > target )
{
sum = sum - window.front();
window.pop_front();
}
if ( sum == target )
{
for( auto k : window )
{
tmp.push_back(k);
}
ans.push_back(tmp);
tmp.clear();
}
}
return ans;
}
};
题目4 最长不含重复字符的子字符串(滑动窗口)
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度.
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if( s.empty() || s.size() == 1 )
{
return s.size();
}
deque<char> window;
set<char> st;
int ans = 0 ;
for ( int i = 0 ; i < s.size() ; i ++ ) // 每个位置的字符串入队列
{
// 如果 st 没有是s[i] 更新 window, st ,ans
if ( ! st.count(s[i]) )
{
window.push_back(s[i]);
st.insert(s[i]);
ans = ans > window.size() ? ans : window.size() ;
}else if ( st.count(s[i]) )
{
ans = ans > window.size() ? ans : window.size() ;
// 队列里是s[i]之前的出队列
char cur = window.front();
while ( cur != s[i] )
{
window.pop_front();
st.erase(cur);
cur = window.front();
}
window.pop_front();
window.push_back(s[i]);
st.insert(s[i]);
}
}
return ans;
}
};