Prob1
给你一个长度为1000000字符串s
然后给你1000000个问题
问a是不是s的子序列
Sol:
序列自动机是用来判断是否是子序列的算法 时间复杂度是 O(len)
nx[i][j] 数组存的是在 s 中第 i 位后面第一个 j 字母出现的位置
Prog:
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e6 + 10;
int n, t, nxt[maxn][30];
char s[maxn], str[maxn];
int main() {
scanf("%s", s+1);
int len = strlen(s+1);
for(int i=len; i; i--) //逆循环
{
for(int j=0; j<26; j++) //26个字母
nxt[i-1][j] = nxt[i][j];
nxt[i-1][s[i]-'a'] = i;
}
int a,b;
/* while (true)
{
cin>>a>>b;
cout<<nxt[a][b]<<endl;
}
*/
scanf("%d", &t);
while(t--)
{
scanf("%s", str);
int lenc = strlen(str), f = 0;
for(int i=0, now=0; i<lenc; i++)
{
now = nxt[now][str[i]-'a'];
if(!now)
{
f = 1;
break;
}
}
if(f) puts("No");
else puts("Yes");
}
}
Prob2:给出一个字符串统计其本质不同的子序列个数
SOL:记忆化搜索
#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 3e3 + 10;
int n, nxt[maxn][30], f[maxn];
char s[105];
int dfs(int x) {
if(f[x])
return f[x];
for(int i=0; i<26; i++)
if(nxt[x][i]) f[x] += dfs(nxt[x][i]);
return ++f[x];
}
int main() {
scanf("%d%s", &n, s+1);
for(int i=n; i; i--) {
for(int j=0; j<26; j++) nxt[i-1][j] = nxt[i][j];
nxt[i-1][s[i]-'a'] = i;
}
int num = dfs(0);
printf("%d\n", num);
}
另一个做法:
zz https://blog.csdn.net/weixin_35338624/java/article/details/88571242
https://blog.csdn.net/oranges_c/article/details/53364269?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1
Leetcode 940:不同的子序列II
题目描述
给定一个字符串 S,计算 S 的不同非空子序列的个数。
因为结果可能很大,所以返回答案模 10^9 + 7.
示例 1:
输入:"abc"
输出:7
解释:7 个不同的子序列分别是 "a", "b", "c", "ab", "ac", "bc", 以及 "abc"。
示例 2:
输入:"aba"
输出:6
解释:6 个不同的子序列分别是 "a", "b", "ab", "ba", "aa" 以及 "aba"。
示例 3:
输入:"aaa"
输出:3
解释:3 个不同的子序列分别是 "a", "aa" 以及 "aaa"。
提示:
S 只包含小写字母。
1 <= S.length <= 2000
解题思路
动态规划,dp[i]定义为以i位置字母结尾的不同子序列个数,当没个字母唯一出现一次时,状态转换方程为dp[i+1] = 2*dp[i],但是根据题目示例,会出现重复的子序列,于是用last[26]记录每个S中的字母最后一次出现的位置,当某一个字母至少出现一次时使用dp[i+1]减去相应的数目就行
int distinctSubseqII(string S) {
int len=S.length();
int mod = 1e9+7;
int dp[len+1] = {0};
int last[26];
memset(last,-1,sizeof(last));
dp[0]=1;
for(int i=0;i<len;i++){
dp[i+1]=(2*dp[i])%mod;
int idx=S[i]-'a';
if(last[idx]>=0){
dp[i+1]=(dp[i+1]-dp[last[idx]] + mod)%mod;
}
last[idx]=i;
}
dp[len] = (dp[len]-1)%mod;
return dp[len];
}
当然此题还可以用后缀数组,后缀自动机等方法来完成 .