字符串匹配(KMP算法)
#include <bits/stdc++.h>
using namespace std;
int const N = 1e6 + 10;
char s[N],pattern[N];
int next[N];
void getnext(){
int len = strlen(pattern);
next[0] = -1;
for(int i=1;i<len;i++){
int k = next[i-1] + 1;
while(k >= 1 && pattern[i] != pattern[k]) k = next[k-1] + 1;
if(k >= 0 && pattern[i] == pattern[k]) next[i] = k;
else next[i] = -1;
}
}
void KMP(){
getnext();
int n = strlen(s);
int m = strlen(pattern);
int i = 0,j = 0;
while(i < n && j < m){
if(s[i] == pattern[j]){
i++, j++;
if(j == m){
printf("%d\n",i - m + 1);
j = next[j-1] + 1;
}
}else if(j >= 1) j = next[j-1] + 1;
else i++;
}
for(int i=0;i<m;i++)
printf("%d ",next[i] + 1);
printf("\n");
}
int main(){
scanf(" %s %s",s,pattern);
KMP();
return 0;
}
最长对称(回文)字串(manacher算法)
#include <bits/stdc++.h>
using namespace std;
int const N = 1000 + 10;
char ss[N],s[N<<1];
int p[N<<1],id;
int main(){
fgets(ss,N,stdin);
int len = strlen(ss);
for(int i=0;i<len-1;i++){ //2*(len-1)+1 = 2len
s[2*i+1] = '#';
s[2*i+2] = ss[i];
}
s[0] = '*', s[2*len-1] = '#', s[2*len] = '\0';
int ans = 0;
for(int i=2;i<=2*len;i++){
int mx = id + p[id];
if(mx > i) p[i] = min(p[2 * id - i],mx - i);
else p[i] = 1;
while(s[i - p[i]] == s[i + p[i]]) p[i]++;
p[i]--;
if(i + p[i] > id + p[id]) id = i;
ans = max(ans,p[i]);
}
printf("%d\n",ans);
return 0;
}
最长回文子序列
-
-
题解
- 给定一个字符串,至少需要添加几个字符,使之成为回文串。
- 答案为字符串的长度减去最长回文子序列。
-
算法一:
-
算法二
- 产生字符串的反序s',对s和s'求最长公共子序列。
-
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int const N = 5000 + 10;
int n;
char s[N];
short int dp[N][N];
int LPS(){
for(int i=0;i<n;i++) dp[i][i] = 1; //长度为1的预处理
for(int len=2;len<=n;len++){ //区间DP,枚举长度
for(int i=0;i+len-1<n;i++){ //[i,i+len-1]
if(s[i] == s[i+len-1]){
dp[i][i+len-1] = dp[i+1][i+len-2] + 2;
}else{
dp[i][i+len-1] = max(dp[i][i+len-2],dp[i+1][i+len-1]);
}
}
}
printf("%d\n",n - dp[0][n-1]);
}
int main(){
scanf("%d",&n);
scanf(" %s",s);
LPS();
return 0;
}
字典树
HDU1251:寻找包含指定前缀的字符串的个数。
#include <bits/stdc++.h>
using namespace std;
int const N = 1e6 + 10;
int nex[N][30];
int sum[N],p;
void insert(char *s){
int len = strlen(s);
int root = 0; //结点的标号
for(int i=0;i<len;i++){
int c = s[i] - 'a';
if(!nex[root][c]) nex[root][c] = ++p;
root = nex[root][c];
sum[root]++;
}
}
int find(char *s){
int len = strlen(s);
int root = 0; //结点的标号
int cnt = 0;
for(int i=0;i<len;i++){
int c = s[i] - 'a';
if(!nex[root][c]) nex[root][c] = ++p;
root = nex[root][c];
}
return sum[root];
}
int main(){
char s[20];
while(gets(s)){ //scanf接受回车放入缓冲区,gets接受回车变成'\0'
if(s[0] == '\0') break;
insert(s);
}
while(~scanf("%s",&s)){
printf("%d\n",find(s));
}
return 0;
}
字符串hash
预处理
xp[0] = 1;
for(int i=1;i<N;i++) xp[i] = xp[i-1] * base; //base取131
从右往左hash
for(int i=n-1;i>=0;i--) h[i] = h[i+1] * base + (ull)s[i];
for(int i=0;i+l-1<n;i++) Hash[i] = h[i] - h[i+l] * xp[l];
从左往右hash
h[0] = (ull)s[0];
for(int i=1;i<=n;i++) h[i] = h[i-1] * base + (ull)s[i];
for(int i=0;i+l-1<n;i++)
Hash[i] = h[i+l-1] - h[i-1] * xp[l];