滑动窗口主要用来解决连续序列的问题,也就是子数组和子字符串相关的问题。滑动窗口的滑动条件就是题目的要求,滑动条件可以借助有序的set、multiset或者无序的unordered_set等来实现。
子数组和子字符串相关问题:CSDN
同时对比子序列和字符串序列的相关问题:CSDN
剑指 Offer II 041. 滑动窗口的平均值
class MovingAverage {
public:
int s;
double sum;
queue q;
/** Initialize your data structure here. */
MovingAverage(int size) {
s = size;
sum = 0;
}
double next(int val) {
if (q.size() < s)
{
sum += val;
q.push(val);
return sum / q.size();
}
else
{
sum -= q.front();
q.pop();
sum += val;
q.push(val);
return sum / s;
}
}
};
/**
* Your MovingAverage object will be instantiated and called as such:
* MovingAverage* obj = new MovingAverage(size);
* double param_1 = obj->next(val);
*/
剑指 Offer II 042. 最近请求次数
class RecentCounter {
public:
queue q;
RecentCounter() {
}
int ping(int t) {
while (!q.empty())
{
int diff = t - q.front();
if (diff > 3000)
q.pop();
else
break;
}
q.push(t);
return q.size();
}
};
/**
* Your RecentCounter object will be instantiated and called as such:
* RecentCounter* obj = new RecentCounter();
* int param_1 = obj->ping(t);
*/
220. 存在重复元素 III
剑指 Offer II 057. 值和下标之差都在给定的范围内
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) {
//相当于用set维护一个窗口
set st;
for (int i = 0; i < nums.size(); i ++)
{
//[nums[i]-t, nums[i]+t]
auto a = st.lower_bound((long) nums[i] - t);
if (a != st.end() && *a <= (long)nums[i] + t)
{
return true;
}
st.insert(nums[i]);
if (i >= k)
st.erase(nums[i-k]);
}
return false;
}
};
class Solution {
public:
bool containsNearbyAlmostDuplicate(vector& nums, int k, int t) {
unordered_map> m;
int n = nums.size();
for (int i=0;i
3. 无重复字符的最长子串
剑指 Offer 48. 最长不含重复字符的子字符串
剑指 Offer II 016. 不含重复字符的最长子字符串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_set w;
int left = 0, right = 0, len = 0;
while(right < s.length())
{
char c = s[right];
if (w.count(c))
{
len = std::max(len, right - left);
w.erase(s[left++]);
continue;
}
else
{
w.insert(c);
}
++right;
}
len = std::max(len, right - left);
return len;
}
};
动态规划的另外一种解法:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector dp(128,-1);//存储每个字符最后出现的位置
int i=0,j=0,res=0;
for(;j
1438. 绝对差不超过限制的最长连续子数组
//链接:https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/solution/jue-dui-chai-bu-chao-guo-xian-zhi-de-zui-5bki/
class Solution {
public:
int longestSubarray(vector& nums, int limit) {
//数组中可能存在重复的数据,所以使用multiset
multiset s;
int n = nums.size();
int left = 0, right = 0;
int ret = 0;
while (right < n)
{
s.insert(nums[right]);
while (*s.rbegin() - *s.begin() > limit)
{
s.erase(s.find(nums[left++]));
}
ret = max(ret, right - left + 1);
right++;
}
return ret;
}
};
480. 滑动窗口中位数
class Solution {
public:
vector medianSlidingWindow(vector& nums, int k) {
vector r;
multiset s;//因为需要排序且可能存在重复的数据,所以选择multiset
int left = 0;
for(auto& i : nums)
{
s.insert(i);
if (s.size() < k)
{
continue;
}
else if (s.size() > k)
{
//这里是关键,题目https://leetcode-cn.com/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/ 与此操作类似
s.erase(s.find(nums[left++]));
}
auto it = s.begin();
double mid = 0.0;
if (k & 0x01 == 1)
{
std::advance(it, k/2);
mid = *it;
}
else
{
std::advance(it, k/2-1);
mid += *it;
std::advance(it, 1);
mid += *it;
mid /= 2;
}
r.push_back(mid);
}
return r;
}
};
76. 最小覆盖子串
//从leetcode 567 https://leetcode-cn.com/problems/permutation-in-string/ 中的方法二修改而来
//因为方法二不要求字符串中全部是小写字母
class Solution {
public:
string minWindow(string s, string t) {
//方法一
string result;
unordered_map need, window;
for (int i = 0;i
567. 字符串的排列
/*
滑动窗口
由于排列不会改变字符串中每个字符的个数,所以只有当两个字符串每个字符的个数均相等时,一个字符串才是另一个字符串的排列。
根据这一性质,记 s1 的长度为 n,我们可以遍历 s2 中的每个长度为 n 的子串,判断子串和 s1
中每个字符的个数是否相等,若相等则说明该子串是 s1 的一个排列。
使用两个数组 cnt1 和 cnt2, cnt1 统计 s1 中各个字符的个数,cnt2统计当前遍历的子串中各个字符的个数。
由于需要遍历的子串长度均为 n,我们可以使用一个固定长度为n 的滑动窗口来维护 cnt2 :
滑动窗口每向右滑动一次,就多统计一次进入窗口的字符,少统计一次离开窗口的字符。
然后,判断 cnt1 是否与 cnt2相等,若相等则意味着 s1 的排列之一是 s2 的子串。
https://leetcode-cn.com/problems/permutation-in-string/solution/zi-fu-chuan-de-pai-lie-by-leetcode-solut-7k7u/
*/
class Solution {
public:
bool checkInclusion(string s1, string s2) {
//方法一
// int n = s1.length(), m = s2.length();
// if (n > m) {
// return false;
// }
// vector cnt1(26), cnt2(26);
// for (int i = 0; i < n; ++i) {
// ++cnt1[s1[i] - 'a'];
// ++cnt2[s2[i] - 'a'];
// }
// if (cnt1 == cnt2) {
// return true;
// }
// for (int i = n; i < m; ++i) {
// ++cnt2[s2[i] - 'a'];
// --cnt2[s2[i - n] - 'a'];
// if (cnt1 == cnt2) {
// return true;
// }
// }
// return false;
//方法二,速度稍低于方法一
unordered_map need, window;
for (int i = 0;i
438. 找到字符串中所有字母异位词
class Solution {
public:
vector findAnagrams(string s, string p) {
vector r;
do
{
int n = p.length(), m = s.length();
if (n > m)
{
break;
}
vector cnt1(26), cnt2(26);
for (int i = 0; i < n; ++i)
{
++cnt1[p[i] - 'a'];
++cnt2[s[i] - 'a'];
}
if (cnt1 == cnt2)
{
r.push_back(0);
}
for (int i = n; i < m; ++i)
{
++cnt2[s[i] - 'a'];
--cnt2[s[i - n] - 'a'];
if (cnt1 == cnt2)
{
r.push_back(i-n+1);
}
}
}while(0);
return r;
}
};
187. 重复的DNA序列
class Solution {
public:
vector findRepeatedDnaSequences(string s) {
int n = s.length();
unordered_map m;
unordered_set st;
for (int i=0;i<=n-10;++i)
{
string str = s.substr(i,10);
if (m.count(str))
st.insert(str);
m[str]++;
}
return vector(st.begin(), st.end());
}
};
674. 最长连续递增序列
//使用滑动窗口
class Solution {
public:
int findLengthOfLCIS(vector& nums) {
int maxLen = 1, left = 0, right = 0;
for (;right < nums.size();++right)
{
if (right > 0)
{
if (nums[right] > nums[right-1])
maxLen = std::max(maxLen, right-left+1);
else
left = right;
}
}
return maxLen;
}
};
2.12
2.13
2.14
2.15
2.16
2.17
2.18
2.19