NC7509B
求含有子序列的最短子串长度为多少
Solution 1
时间复杂度:
思路:由于是唯一的,没有重复的字符,所以可以用十个指针维护十个位置,使得满足题目要求,每个指针指向中的字符,然后遍历一边,记录满足要求的最小值即可。
Code
#include<bits/stdc++.h> #define fi first #define se second #define mp make_pair using namespace std; typedef long long ll; typedef pair<int,int>P; const double eps = 1e-8; const int NINF = 0xc0c0c0c0; const int INF = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll N = 1e6 + 5; void solve(){ string s;cin>>s; int nn=s.size(); vector<int> V[30]; for(int i=0;i<nn;i++) V[s[i]-'a'].emplace_back(i); int ans=INF; int p=0,u=0,l=0,e=0,y=0,a=0,k=0,n=0,o=0,i=0; for(;p<V['p'-'a'].size();p++){ for(;u<V['u'-'a'].size();){ if(V['u'-'a'][u]<V['p'-'a'][p]) {u++;continue;} for(;l<V['l'-'a'].size();){ if(V['l'-'a'][l]<V['u'-'a'][u]) {l++;continue;} for(;e<V['e'-'a'].size();){ if(V['e'-'a'][e]<V['l'-'a'][l]) {e++;continue;} for(;y<V['y'-'a'].size();){ if(V['y'-'a'][y]<V['e'-'a'][e]) {y++;continue;} for(;a<V['a'-'a'].size();){ if(V['a'-'a'][a]<V['y'-'a'][y]) {a++;continue;} for(;k<V['k'-'a'].size();){ if(V['k'-'a'][k]<V['a'-'a'][a]) {k++;continue;} for(;n<V['n'-'a'].size();){ if(V['n'-'a'][n]<V['k'-'a'][k]) {n++;continue;} for(;o<V['o'-'a'].size();){ if(V['o'-'a'][o]<V['n'-'a'][n]) {o++;continue;} for(;i<V['i'-'a'].size();){ if(V['i'-'a'][i]<V['o'-'a'][o]) {i++;continue;} else { ans=min(ans,V['i'-'a'][i]-V['p'-'a'][p]+1); goto X; } } goto X; } goto X; } goto X; } goto X; } goto X; } goto X; } goto X; } goto X; } X:; } if(ans==INF) ans=-1; cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(false); cin.tie(0); int T;cin>>T; while(T--){ solve(); } return 0; }
Update
博主当时觉得这样个比较有趣,但是实际上这样的思想用dfs写起来会更优雅一些?
于是乎在上课的时候脑补了一个dfs版本的上述思想解法。
#include <bits/stdc++.h> #define fi first #define se second #define mp make_pair using namespace std; typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int NINF = 0xc0c0c0c0; const int INF = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll N = 1e6 + 5; string s,t="puleyaknoi"; int ans,p[15]; vector<int> V[30]; void dfs(int x){ if(x==10){ ans=min(ans,V[t[9]-'a'][p[9]]-V[t[0]-'a'][p[0]]+1); return; } while(p[x]<V[t[x]-'a'].size()){ if(x){ if(V[t[x]-'a'][p[x]]>V[t[x-1]-'a'][p[x-1]]) {dfs(x+1);return;} }else dfs(x+1); p[x]++; } return; } void solve(){ ans=INF; for(int i=0;i<10;i++) p[i]=0; for(int i=0;i<26;i++) V[i].clear(); cin>>s; int sz=s.size(); for(int i=0;i<sz;i++) V[s[i]-'a'].push_back(i); dfs(0); if(ans==INF) ans=-1; cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int T;cin>>T; while(T--) solve(); return 0; }
Solution 2
DP记录离当前字符最近的上一个字符的位置。
#include <bits/stdc++.h> #define fi first #define se second #define mp make_pair using namespace std; typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int NINF = 0xc0c0c0c0; const int INF = 0x3f3f3f3f; const ll mod = 1e9 + 7; const ll N = 1e5 + 5; string s,t="puleyaknoi"; unordered_map<char,int> M; int f[N][10],n,ans; void init(){ for(int i=0;i<10;i++) M[t[i]]=i; } void solve(){ cin>>s; n=s.size(); s=" "+s; ans=INF; for(int i=1;i<=n;i++){ for(int j=0;j<10;j++) f[i][j]=f[i-1][j]; if(!M.count(s[i])) continue; int id=M[s[i]]; if(!id) f[i][id]=i; else f[i][id]=f[i-1][id-1]; if(id==9 && f[i][id]) ans=min(ans, i-f[i][id]+1); } if(ans==INF) ans=-1; cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); init(); int T;cin>>T; while(T--) solve(); return 0; }