目录
209. 长度最小的子数组
class Solution {
public:
int minSubArrayLen(int S, vector<int>& nums) {
int n = nums.size();
int s = 0,t = 0;
int res = INT_MAX;
int sum = 0;
while(1)
{
while(t <= n-1 && sum < S)sum+=nums[t++];//无效状态则一直更新右端点
if(sum < S)break;
res = min(res,t-s);
sum -= nums[s++];
}
if(res == INT_MAX)return 0;
return res;
}
};
POJ 3320
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<string>
#include<cstring>
#include<vector>
#include<functional>
#include<utility>
#include<set>
#include<map>
using namespace std;
int a[1000000+5];
int P;
int main()
{
cin>>P;
for(int i=0;i<P;i++)
scanf("%d",&a[i]);
set<int>all;
for(int i=0;i<P;i++)
all.insert(a[i]);
int n=all.size();//知识点总种类
int s=0,t=0,num=0;
map<int,int>mp;
int res=P;
while(1)
{
while(t<P&&num<n)
if(mp[a[t++]]++==0)num++;//出现新知识点。
if(num<n)break;
res=min(res,t-s);
if(--mp[a[s++]]==0)num--;//某个知识点出现次数变为0;
}
cout<<res<<endl;
}
leetcode---992
class Solution {
public:
int subarraysWithKDistinct(vector<int>& A, int K) {
int n = A.size();
vector<int>left(n,n);
vector<int>right(n,n);
int ans = 0;
find(left,A,K);
find(right,A,K+1);
if(right[0] > left[0])ans+=right[0]-left[0];
for(int i = 1;i<n;++i){
// cout << left[i] << " " << right[i] << endl;
ans += (right[i] - left[i]);//前缀和思想
}
return ans;
}
void find(vector<int> &last,vector<int>&a,int k){
int n = a.size();
vector<int> vis(n+1,0);
int s = 0,t = 0,num = 0;
while(1){
while(t<n && num < k){
if(vis[a[t++]]++ == 0)num++;
}
if( num < k){break;}
last[s] = t-1;
if(--vis[a[s++]] == 0)num--;
}
}
};
76. 最小覆盖子串
这题有歧义,包含所有字母一开始理解为了包含所有的就可以了,后来看样例是 数量也要正确。
class Solution {
public:
string minWindow(string s, string t) {
int l = 0,r = 0;
int cnt = t.size();
vector<int>win(265,0);
vector<int>need(256,0);
for(auto&x :t)need[x]++;
int suc = t.size();
int d = 0x3f3f3f3f;
int head = 0;
int num = 0;
while(1)
{
while(r<s.size() && num < suc)//无效状态一直更新right
{
if(need[s[r]] && win[s[r]] < need[s[r]])
{
++num;
}
win[s[r]]++;
++r;
}
if(num < suc)break;
if(d>r-l)d=r-l,head=l;
//有效一直更新left
win[s[l]]--;
if(need[s[l]] && win[s[l]] < need[s[l]])
{
--num;
}
++l;
}
return d == 0x3f3f3f3f?"":s.substr(head,d);
}
};
30. 串联所有单词的子串
把等长字符串等价成一个值,发现和上面的题类似,但是这道题不是求最优,而是求连续出现的区间(也就是中间不能夹杂其他元素),这时候每次右端点往前更新的时候出现其他元素就要更新状态为初始态了;右端点更新带来的非法状态,左端点要一直往前挪,直至非法状态消除。
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
unordered_map<string,int>mp1,mp2;
for(auto &x:words)mp1[x]++;
if(!words.size() || s.empty())return std::vector<int>();
int cnt = words.size(), len = words[0].size();
std::vector<int> ans;
for(int i = 0; i < len; ++i)
{
int left = i,right = i,num = 0;
mp2.clear();
while(right + len <= s.size())
{
string next_str = s.substr(right,len);
right = right + len;
if(!mp1[next_str])//新增字符串不包含在字典中
{
left = right;
num = 0;
mp2.clear();
continue;
}
mp2[next_str]++;
num++;
while(mp2[next_str] > mp1[next_str])//右端点向前一步,导致非法状态,需要left往前走
{
string left_next_str = s.substr(left,len);
num--;
mp2[left_next_str]--;
left += len;
}
cout << left << " " << right << " " << num << endl;
if(num == cnt)ans.push_back(left);
}
}
return ans;
}
};