字符串总结?

版权声明:欢迎转载欢迎评论! 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;
}

猜你喜欢

转载自blog.csdn.net/rabbit_ZAR/article/details/85223972