版权声明:欢迎转载欢迎评论! https://blog.csdn.net/rabbit_ZAR/article/details/85223972
其实就是模板汇总好伐
1、字符串hash
可以解决一切字符串问题。
复杂度成迷。
#include<bits/stdc++.h>
using namespace std;
#define maxn 10000
#define read(x) scanf("%d",&x)
#define maxm 1500
#define ull unsigned long long
#define P 131
int n;
char a[maxn+5][maxm+5];
ull Hash[maxn+5];
ull make_hash(int x) {
ull y=0;
int len=strlen(a[x]);
for(int i=0;i<len;i++) {
y=y*P+a[x][i]-'a'+1;
}
return y;
}
int main() {
read(n);
for(int i=1; i<=n; i++) {
scanf("%s",a[i]);
Hash[i]=make_hash(i);
}
sort(Hash+1,Hash+n+1);
int cnt=0;
for(int i=1;i<=n;i++) {
if(Hash[i]!=Hash[i-1]) cnt++;
}
printf("%d",cnt);
return 0;
}
2、manacher算法
求最长回文子串长度。
复杂度O(n)
#include<bits/stdc++.h>
using namespace std;
#define maxn 22000000
char b[maxn+5],a[maxn+5];
int n;
int p[maxn+5];
int main() {
scanf("%s",b);
n=strlen(b);
for(int i=0;i<n;i++) {
a[i*2]='#';
a[i*2+1]=b[i];
}
a[n*2]='#';
n*=2;
n-=1;
int id=0,mx=0;
p[0]=1;
for(int i=1;i<=n;i++) {
if(i<mx) p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
while(i-p[i]>=0&&a[i+p[i]]==a[i-p[i]]) p[i]++;
if(p[i]+i>mx) {
mx=p[i]+i;
id=i;
}
}
int ans=0;
for(int i=1;i<=n;i++) {
ans=max(ans,p[i]-1);
}
printf("%d",ans);
return 0;
}
3、kmp
单文本串、单模式串 字符串匹配。
复杂度O(n)
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000
char a[maxn+5],b[maxn+5]; //a为文本串,b为模式串
int n,m; //a、b的长度
int nxt[maxn+5]={0}; //0~i的公共前后缀长
void readin() { //读入
scanf("%s%s",a,b);
n=strlen(a),m=strlen(b);
}
void make_nxt() { //初始化nxt数组
nxt[0]=-1; //为了回避数组超下界,这里的nxt[i+1]表示nxt[i]
for(int i=0;i<m;i++) {
int j=nxt[i]; //[0,j]始终等于[i-j,i]
while(b[i]!=b[j]&&j>=0) { //通过[1,i]的公共前后缀长来推导[1,i+1]的公共前后缀长
j=nxt[j]; //[1,nxt[j]]的最长公共前后缀,一定也同时是[1,j]的公共前后缀,同时是[1,i]的公共前后缀
}
nxt[i+1]=j+1;
}
//此时的nxt需整体前移
for(int i=0;i<m;i++) nxt[i]=nxt[i+1];
}
void mtch(){ //匹配
int j=0;
for(int i=0;i<n;i++) {
while(j&&a[i]!=b[j]) { //找到第一个b[0,j]可以匹配上a[0,i]的位置
j=nxt[j-1];
}
if(a[i]==b[j]) j++; //为了防止j==0要加一步判断
if(j==m){
printf("%d\n",i-m+2); //输出
j=nxt[j-1];
}
}
for(int i=0;i<m;i++) printf("%d ",nxt[i]);
}
int main(){
readin();
make_nxt();
mtch();
return 0;
}
4、AC自动机
本质 Trie + kmp 。
单文本串、多模式串 字符串匹配。
复杂度大概O(n+m)。
#include<iostream>
#include<cstdio>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
using namespace std;
#define maxn 1000000
#define maxs 26
struct AC {
int ch[maxn+5][maxs];
int val[maxn+5];
int sz;
int Fail[maxn+5];
int sum;
int que[maxn+5];
void clear() {
memset(ch,0,sizeof(ch));
memset(val,0,sizeof(val));
memset(Fail,0,sizeof(Fail));
sz=sum=0;
}
void insert(char* x,int len) {
int u=0;
for(int i=0; i<len; i++) {
int y=x[i]-'a';
if(!ch[u][y]) {
ch[u][y]=++sz;
}
u=ch[u][y];
}
val[u]++;
}
void make_fail() {
queue<int> que;
for(int i=0; i<maxs; i++) {
if(ch[0][i]) que.push(ch[0][i]);
}
while(!que.empty()) {
int u=que.front();
que.pop();
for(int i=0; i<maxs; i++) {
if(ch[u][i]==0) {
ch[u][i]=ch[Fail[u]][i];
continue;
}
que.push(ch[u][i]);
Fail[ch[u][i]]=ch[Fail[u]][i];
}
}
}
void find(char* s,int len) {
int j=0;
for(int i=0; i<len; i++) {
int x=s[i]-'a';
j=ch[j][x];
for(int k=j; k&&(~val[k]); k=Fail[k]) {
sum+=val[k];
val[k]=-1;
}
}
}
};
int n;
AC ac;
int main() {
ac.clear();
scanf("%d",&n);
char x[maxn+5];
for(int i=0; i<n; i++) {
scanf("%s",x);
ac.insert(x,strlen(x));
}
ac.make_fail();
char s[maxn+5];
scanf("%s",s);
ac.find(s,strlen(s));
printf("%d",ac.sum);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
#define maxn 150
#define maxd 70
#define maxm maxn*maxd
#define maxa 1000000
#define s 26
int n;
struct AC {
int ch[maxm+5][s+5],m;
int val[maxm+5];
char a[maxa+5];
int fail[maxm+5];
char lst[maxn+5][maxd+5];
int mp[maxn+5];
int sum[maxm+5];
void clr() {
memset(ch,0,sizeof(ch));
memset(val,0,sizeof(val));
memset(fail,0,sizeof(fail));
memset(mp,0,sizeof(mp));
memset(sum,0,sizeof(sum));
m=0;
}
void insert(char* x,int len,int j) {
int u=0;
for(int i=0; i<len; i++) {
int y=x[i]-'a'+1;
if(!ch[u][y]) {
ch[u][y]=++m;
}
u=ch[u][y];
}
val[u]++;
mp[j]=u;
}
void make_fail() {
queue<int> que;
for(int i=1; i<=s; i++) {
if(ch[0][i]) que.push(ch[0][i]);
}
while(!que.empty()) {
int u=que.front();
que.pop();
for(int i=1; i<=s; i++) {
if(ch[u][i]) {
que.push(ch[u][i]);
fail[ch[u][i]]=ch[fail[u]][i];
} else {
ch[u][i]=ch[fail[u]][i];
}
}
}
}
void find() {
int len=strlen(a);
int j=0;
for(int i=0; i<len; i++) {
int x=a[i]-'a'+1;
j=ch[j][x];
for(int k=j; k; k=fail[k]) sum[k]++;
}
}
void readin() {
for(int i=1; i<=n; i++) {
scanf("%s",lst[i]);
int y=strlen(lst[i]);
insert(lst[i],y,i);
}
make_fail();
scanf("%s",a);
}
void print() {
int ans=0;
for(int i=1; i<=m; i++) {
if(val[i]) ans=max(ans,sum[i]);
}
printf("%d\n",ans);
for(int i=1; i<=n; i++) {
if(sum[mp[i]]==ans) {
printf("%s\n",lst[i]);
}
}
}
};
AC ac;
int main() {
while(~scanf("%d",&n)&&n) {
ac.clr();
ac.readin();
ac.find();
ac.print();
}
return 0;
}
5、SA
后缀排序和LCS问题,复杂度O(n log n)
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000000
int n,m;
char a[maxn+5];
int sa[maxn+5],rk[maxn+5];
int tax[maxn+5],tp[maxn+5];
void readin() {
scanf("%s",a+1);
n=strlen(a+1);
}
void rsort() {
memset(tax,0,sizeof(tax));
for(int i=1;i<=n;i++) tax[rk[tp[i]]]++;
for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
for(int i=n;i>=1;i--) sa[tax[rk[tp[i]]]--]=tp[i];
}
void makesa() {
for(int i=1;i<=n;i++) rk[i]=(int)a[i],tp[i]=i;
rsort();
for(int k=1;k<=n;k<<=1) {
int num=0;
for(int i=n-k+1;i<=n;i++) tp[++num]=i;
for(int i=1;i<=n;i++) if(sa[i]>k) tp[++num]=sa[i]-k;
rsort();
swap(rk,tp);
rk[sa[1]]=1;
num=1;
for(int i=2;i<=n;i++) {
if(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k]) rk[sa[i]]=num;
else rk[sa[i]]=++num;
}
if(num==n) break;
m=num;
}
}
int main() {
readin();
m=122;
makesa();
for(int i=1;i<=n;i++) printf("%d ",sa[i]);
return 0;
}