字符串各算法学习

来源:互联网 发布:淘宝改高价 编辑:程序博客网 时间:2024/06/05 20:28

在网络赛期间罢赛不做题了过来写博客真是一种罪过,然而被零封实在是没有勇气坚持最后一个小时。。。。

两个队友都不在,单挑太水了


————————————————————————————————————————————————————————

进入正题

字符串常用算法


Part 1:字符Hash

模版上述地方有,根据题目对自己的理解进行解释:

HDOJ 4821

题意:给定m和l和一个字符串,

求该串中连续m个长为l的子串互不重复的数目

char s[maxn];ull base[maxn],Hash[maxn];map<ull,int> mp;int main(){//input;int m,l,i,len,ans;base[0]=1;for(i=1;i<maxn;i++) base[i]=base[i-1]*seed;while(scanf("%d%d",&m,&l)!=EOF){scanf("%s",s);ans=0;len=strlen(s);Hash[len]=0;for(i=len-1;i>=0;i--)Hash[i]=Hash[i+1]*seed+s[i]-'a';for(i=0;i<l&&i+m*l<len;i++){//枚举以i位置为起点,长度为m*l的子串是否合法 mp.clear();for(int j=i;j<i+m*l;j+=l){// ull temp=Hash[j]-Hash[j+l]*base[l];mp[temp]++;}if (mp.size()==m) ans++;for(int j=i+m*l;j+l<=len;j+=l){//更换起点,i+km为起点依次往后推 ull temp=Hash[j-m*l]-Hash[j-(m-1)*l]*base[l];mp[temp]--;if (!mp[temp]) mp.erase(temp);temp=Hash[j]-Hash[j+l]*base[l];mp[temp]++;if (mp.size()==m) ans++;}}printf("%d\n",ans);}return 0;}

HDOJ 4080

/*字符串题目注意:Hash,Rank这类单词一定首字母大写,不然CE题意:给定一个字符串和出现次数k,  找出至少出现k次的最长的子串长度以及其最后一次出现的位置(首字符的位置) 二分判断某个长度是否可行,找到最大的。。。。按照哈希值的大小排序:越大的位数“相对” 越长 */int l,len,pos,Rank[maxn];ull Hash[maxn],xp[maxn],haha[maxn];char str[maxn];bool cmp(int a,int b){/*if (haha[a]==haha[b]) return a<b;return haha[a]<haha[b];*/return (haha[a]!=haha[b])?(haha[a]<haha[b]):(a<b);}bool solve(int mid){int c=1;pos=-1;for(int i=0;i<len-mid+1;i++){Rank[i]=i;haha[i]=Hash[i]-Hash[i+mid]*xp[mid];}sort(Rank,Rank+len-mid+1,cmp);//注意第二个参数,len-mid+1描述的是数组中元素个数//开始找for(int i=0;i<len-mid+1;i++){if (i==0||haha[Rank[i]]!=haha[Rank[i-1]]) c=1;else{c++;if (c>=l) pos=max(pos,Rank[i]);}}return pos>=0;}int main(){//input;while(scanf("%d",&l)!=EOF){if (!l) break;scanf("%s",str);len=strlen(str);if (l==1){//特判,串长为1 printf("%d %d\n",len,0);continue;}memset(Hash,0,sizeof(Hash));memset(xp,0,sizeof(xp));xp[0]=1;for(int i=len-1;i>=0;i--)Hash[i]=Hash[i+1]*x+str[i]-'a';for(int i=1;i<len;i++) xp[i]=xp[i-1]*x;if (!solve(1)){//又是细节判断,无解输出 puts("none");continue;}int low=1,high=len,mid;while(low+1<high){mid=(low+high)>>1;if (solve(mid)) low=mid;else high=mid;}solve(low);printf("%d %d\n",low,pos);}return 0;}

Trie(字典树)原理


POJ3630

POJ3630题解


KMP算法

我bin带你飞的专题直接刷爆把:练习KMP



AC自动机(听妈妈说学过这个算法就一定AK)

看过算法之后,学学我bin神的模板保证比赛平安:

HDOJ 2222


struct Trie{int next[500010][26],fail[500010],end[500010];int root,L;int newnode(){for(int i=0;i<26;i++) next[L][i]=-1;end[L++]=0;return L-1;}void init(){L=0;root=newnode();}void insert(char buf[]){int len=strlen(buf);int now=root;for(int i=0;i<len;i++){if (next[now][buf[i]-'a']==-1) next[now][buf[i]-'a']=newnode();now=next[now][buf[i]-'a'];}end[now]++;}void build(){queue<int> Q;fail[root]=root;for(int i=0;i<26;i++)if (next[root][i]==-1) next[root][i]=root;else{fail[next[root][i]]=root;Q.push(next[root][i]);}while(!Q.empty()){int now=Q.front();Q.pop();for(int i=0;i<26;i++)if (next[now][i]==-1)next[now][i]=next[fail[now]][i];else{fail[next[now][i]]=next[fail[now]][i];Q.push(next[now][i]);}}}int query(char buf[]){int len=strlen(buf);int now=root;int res=0;for(int i=0;i<len;i++){now=next[now][buf[i]-'a'];int temp=now;while(temp!=root){res+=end[temp];end[temp]=0;temp=fail[temp];}}return res;}}; char buf[1000010];Trie ac;int main(){//input;int T,n;scanf("%d",&T);while(T--){scanf("%d",&n);ac.init();for(int i=0;i<n;i++){scanf("%s",buf);ac.insert(buf);}ac.build();scanf("%s",buf);printf("%d\n",ac.query(buf));}return 0;}


习题链接:我bin带你飞——AC自动机专题

第一题HDOJ2222模板题

第二题HDOJ2896需要改动模板:对end数组中记录各个字符串的编号

第三题HDOJ3065需要改动模板:每个字符串在模式串之中匹配了几次(在query中添加一个标记数组)

第四题ZOJ3430需要添加一个base64的解码算法。。。弱写了太久,还是WA,直接搬运我bin的吧:


unsigned char buf[2050];int tot;char str[4000];unsigned char s[4000];unsigned char Get(char ch){    if( ch>='A'&&ch<='Z' )return ch-'A';    if( ch>='a'&&ch<='z' )return ch-'a'+26;    if( ch>='0'&&ch<='9' )return ch-'0'+52;    if( ch=='+' )return 62;    else return 63;}void change(unsigned char str[],int len){    int t=0;    for(int i=0;i<len;i+=4)    {        buf[t++]=((str[i]<<2)|(str[i+1]>>4));        if(i+2 < len)            buf[t++]=( (str[i+1]<<4)|(str[i+2]>>2) );        if(i+3 < len)            buf[t++]= ( (str[i+2]<<6)|str[i+3] );    }    tot=t;}main():    int n,m;    while(scanf("%d",&n) == 1)    {        ac.init();        for(int i = 0;i < n;i++)        {            scanf("%s",str);            int len = strlen(str);            while(str[len-1]=='=')len--;            for(int j = 0;j < len;j++)            {                s[j] = Get(str[j]);            }            change(s,len);            ac.insert(buf,tot,i);        }


0 0
原创粉丝点击