本文题目均取自LeetCode
滑动窗口:同向双指针
时间复杂度:O(n)
文章目录
209.长度最小的数组
1.题目描述
2.思路
注意审题,本题全是正整数,固一定满足单调性,下面我们通过画图来解决此题
取最小,则就将上一步取到的最小长度和这一步取到的调用min函数即可
3.代码实现
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size(),sum = 0,len = 100010;
for(int left = 0,right = 0;right < n;right++)
{
sum += nums[right];
while(sum >= target)
{
len = min(len,right-left+1);
sum -= nums[left++];
}
}
return len==100010 ? 0 : len;
}
};
3.无重复字符的最长字串
1.题目描述
2.思路
我们本题用数组模拟哈希表,用string字符组成做哈希表下标,若哈希表某个下标对应值大于1,就说明出现重复,接着移动窗口,left++,直到不存在重复为止
3.代码实现
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int hash[128] = {0};
int n = s.size();
int ans = 0;
for(int left = 0,right = 0;right < n;right++)
{
hash[s[right]]++;
while(hash[s[right]] > 1)
hash[s[left++]]--;
ans = max(ans,right-left+1);
}
return ans;
}
};
1004.最大连续1的个数 |||
1.题目描述
2.思路
本题先对0的个数进行计数,移动右窗口,当0的个数zero大于k时,进行调整窗口,右移左窗口,直到left找到0为止,此时让left移动到该0元素的下一个位置,退出调整,继续移动右窗口,直到right不小于n为止
3.代码实现
class Solution {
public:
int longestOnes(vector<int>& nums, int k) {
int n = nums.size();
int zero = 0;//记录0
int len = 0;
for(int left = 0,right = 0;right < n;right++)
{
if(nums[right] == 0)
zero++;
while(zero > k)
if(nums[left++]==0)
zero--;
len = max(len,right-left+1);
}
return len;
}
};
1658.将x减到0的最小操作数
1.题目描述
2.思路
这题要是直接按照题目要求移除会非常麻烦,所以我们仔细观察题目,可以将题目转换成:找出最长的子数组的长度,所有元素的和正好是sum - x
3.代码实现
class Solution {
public:
int minOperations(vector<int>& nums, int x) {
int n = nums.size();
int sum = 0;
for(int a : nums) sum += a;
int target = sum - x;
if(target < 0)
return -1;
int ans = -1;
for(int left = 0,right = 0,sum1 = 0;right < n;right++)
{
sum1 += nums[right];
while(sum1 > target)
sum1 -= nums[left++];
if(sum1 == target)
ans = max(ans,right-left+1);
}
if(ans == -1) return -1;
else
return n - ans;
}
};
904.水果成篮
1.题目描述
2.思路
本题依旧采用哈希表,这里用来存储水果的种类,当种类大于2时就要进行调整窗口
但是本题因为测试范围的问题,我们可以取巧用数组模拟哈希表,降低程序运行时间
3.代码实现
//注释部分为本题优化前代码
class Solution {
public:
int totalFruit(vector<int>& f) {
//unordered_map<int,int> hash;
int hash[100010] = {0};//优化后的哈希表
int n = f.size();
int ans = 0;
//for(int left = 0,right =0;right < n;right++)
for(int left = 0,right =0,kinds = 0;right < n;right++)
{
if(hash[f[right]] == 0) kinds++;//维护水果种类
hash[f[right]]++;
//while(hash.size() > 2)
while(kinds > 2)
{
hash[f[left]]--;
if(hash[f[left]] == 0)
//hash.erase(f[left]);
kinds--;
left++;
}
ans = max(ans,right-left+1);
}
return ans;
}
};
438.找到字符串中所有字母异位词(含优化)
1.题目描述
2.思路
如图
代码实现
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ans;//存储答案索引
unordered_map<int,int> hashs;//记录s各字符个数
unordered_map<int,int> hashp;//记录p各字符个数
int n = s.size();
int m = p.size();
for(int i = 0;i<m;i++)
hashp[p[i]]++;
for(int left = 0,right = 0;right<n;right++)
{
hashs[s[right]]++;
if(right - left + 1 == m)
{
int flag = 1;
for(int i = 0;i<hashs.size();i++)
{
if(hashs[i] != hashp[i])
flag = 0;
}
if(flag)
ans.push_back(left);
hashs[s[left]]--;
left++;
}
}
return ans;
}
};
但这样无论空间还是时间都太大了,在此基础上我们可以先用数组模拟进行初步优化
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ans;//存储答案索引
int hashs[256] = {0};//记录s各字符个数
int hashp[256] = {0};//记录p各字符个数
int n = s.size();
int m = p.size();
for(int i = 0;i<m;i++)
hashp[p[i]]++;
for(int left = 0,right = 0;right<n;right++)
{
hashs[s[right]]++;
if(right - left + 1 == m)
{
int flag = 1;
for(int i = 0;i<26;i++)
{
if(hashs['a' + i] != hashp['a' + i])
flag = 0;
}
if(flag)
ans.push_back(left);
hashs[s[left]]--;
left++;
}
}
return ans;
}
};
这样明显快了很多,时间复杂度大概是26n,也就是O(n),但这也只适用于本题,那还能不能进一步优化呢?
这里我们使用count来统计有效字符数,当count和p的长度一样时,输出left值
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> ret;
int hash1[26] = {0};
int count = 0;
for(auto i: p)
hash1[i-'a']++;
int hash2[26] = {0};
int m = p.size();
int n = s.size();
for(int left = 0,right = 0;right < n;right++)
{
char in = s[right];
if(++hash2[in - 'a'] <= hash1[in - 'a'])
count++;
if(right - left + 1 > m)
{
char out = s[left++];
if(hash2[out - 'a']-- <= hash1[out - 'a'])
count--;
}
if(count == m) ret.push_back(left);
}
return ret;
}
};
这里我们在比较两个哈希表里数据是否一样时,我们还可以不适用哈希表存储数据,而是利用vector,因为vector中重载了==运算符,代码如下
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int n = s.size();
int m = p.size();
if(n<m)
return vector<int>();
vector<int> ans;
vector<int> ncount(26);
vector<int> mcount(26);
for(int i = 0;i<m;i++)
{
++ncount[s[i] - 'a'];
++mcount[p[i] - 'a'];
}
if(ncount == mcount)
ans.emplace_back(0);
for(int i = 0;i<n-m;i++)
{
--ncount[s[i] - 'a'];
++ncount[s[i+m] - 'a'];
if(ncount == mcount)
ans.emplace_back(i+1);
}
return ans;
}
};