滑动窗口
209. 长度最小的子数组
题目描述
方法1 暴力搜索 复杂度为O(n3)
int minSubArrayLen(int s, vector<int>& nums) {
//int sum = 0;
int minlen = nums.size() + 1;
for (int i = 0;i < nums.size();i++)
{
int subsum = 0;
for (int j = i;j < nums.size();j++)
{
int len = j - i + 1;
subsum += nums[j];
if (subsum >= s)
{
minlen = min(minlen, len);
}
}
}
return minlen == nums.size() + 1 ? 0 : minlen;
}
方法2 滑动窗口
int minSubArrayLen(int s, vector<int>& nums) {
//int sum = 0;
int minlen = nums.size() + 1;
int l = 0;//[l,r]为满足条件的字符串
int r = -1;
int sum = 0;
while (l < nums.size())
{
if(sum<s&&r+1<nums.size())
{
sum += nums[++r];
}
else
{
sum -= nums[l++];
}
if (sum >= s)
{
minlen = min(minlen, r - l + 1);
}
}
return minlen == nums.size() + 1 ? 0 : minlen;
}
方法3 二分查找
int binarysearch(int l, int r, int* nums, int target)
{
int k = l;//[l..mid]<target
while (l <= r)
{
int mid = l + (r - l) / 2;
if (l==r)//循环结束条件
{
if(nums[l] >=target)
return l;
else //没有找到
{
return -1;
}
}
else if (nums[mid] < target)//小于 mid不可能是目标
{
l = mid+1;//抛弃mid
}
else//大于等于目标 那么mid有可能是要找到目标
{
r = mid;
}
}
return -1;//一般不会出现
}
int minSubArrayLen(int s, vector<int>& nums) {
//int sum = 0;
int minlen = nums.size() + 1;
int len = nums.size();
if (len == 0)return 0;
int* sums = new int[len];
sums[0] = nums[0];
for (int i = 1;i < len;i++)
{
sums[i] = sums[i - 1] + nums[i];//求和
}
int l = 0;
int r = len - 1;
for (int i = 0;i < len;i++)
{
int target = s + sums[i] - nums[i];//保证s[j]-s[i]+nums[i]>=s 所以 s[j]>=s+s[i]-nums[i]
int ret = binarysearch(i, r, sums, target);//二分查找
if (ret - i + 1 < minlen && ret != -1)
{
minlen = ret - i + 1;
}
}
return minlen == nums.size() + 1 ? 0 : minlen;
}
3. 无重复字符的最长子串
题目描述
方法1 标准格式的滑动窗口
int lengthOfLongestSubstring1(string s) {
int freq[256] = { 0 };
int l = 0, r = -1;
int res = 0;
while (l < s.size())
{
if (r + 1 < s.size() && freq[s[r + 1]] == 0)
{
freq[s[++r]]++;
}
else
{
freq[s[l++]]--;
}
res = max(res, r - l + 1);
}
return res;
}
方法2 使用while循环直到将左指针滑到合适位置
比较复杂 逻辑混乱 边界还容易错
int lengthOfLongestSubstring(string s) {
int freq[256] = { 0 };
int l = 0, r = -1;
int res = 0;
while (l < s.size() && r + 1 < s.length())
{
if (r + 1 < s.length() && freq[s[r + 1]] == 0)
{
freq[s[++r]] ++;
}
else
{
while (freq[s[r + 1]] != 0)
{
freq[s[l++]]--;
}
if (r + 1 < s.length())
{
freq[s[++r]] ++;
}
}
res = max(res, r - l + 1);
}
return res;
}
438. 找到字符串中所有字母异位词
题目描述
算法实现
vector<int> findAnagrams(string s, string p) {
int freq1[256] = { 0 };
int freq2[256] = { 0 };
vector<int> res;
for (int i = 0;i < p.length();i++)
{
freq2[p[i]]++;
}
int l = 0;
int r = -1;
while (l < s.size())
{
if (freq1[s[r + 1]] < freq2[s[r + 1]])
{
r++;
freq1[s[r]]++;
}
else
{
freq1[s[l]]--;
l++;
}
if(r-l+1==p.size())
{
res.push_back(l);
}
}
return res;
}
三级目录
76. 最小覆盖子串
题目描述
算法实现
感觉不是很清楚 但是做对了 有空再看
string minWindow(string s, string t) {
int freq1[256] = { 0 };
int freq2[256] = { 0 };
vector<int> res;
for (int i = 0;i < t.length();i++)
{
freq2[t[i]]++;
}
int need = t.length();
int l = 0;
int fl = -1;
int fr = -1;
int r = -1;
int mins = s.size()+1;
while (l < s.size())
{
if (need > 0&&r+1<s.size())
{
r++;
freq1[s[r]]++;
if (freq1[s[r ]]>0&& freq1[s[r]] <= freq2[s[r ]])
{
need = need -1;
}
}
else
{
freq1[s[l]]--;
if (freq1[s[l]] < freq2[s[l]] && freq2[s[l]] != 0)
{
need++;
}
l++;
}
if (need == 0)
{
if (r - l + 1 < mins)
{
mins = min(mins, r - l + 1);
fl = l;
fr = r;
}
}
}
string ret;
if (mins != s.size() + 1)
{
for (int i = fl;i <= fr;i++)
{
ret+=s[i];
}
}
return ret;
}
总结滑动窗口公式
int l = 0;//左边界
int r = -1;//右边界
while (l < s.size())//停止条件一般为右边界小于size
{
if (freq1[s[r + 1]] < freq2[s[r + 1]])//右指针滑动条件 可以加上边界条件 如r + 1 < s.size() r+1位置的元素满足条件
{
r++;
freq1[s[r]]++;
}
else
{
freq1[s[l]]--;//否则就左指针滑动
l++;
}
if(r-l+1==p.size())//题目要求 最长最短等等目的
{
res.push_back(l);
}
}
return res;
}