日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法分类整理+模板②:字符串处理

發(fā)布時間:2024/4/17 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法分类整理+模板②:字符串处理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本周訓(xùn)練賽出了一道kmp模板題,但是由于長時間沒有復(fù)習(xí)字符串處理算法,而且學(xué)習(xí)時也并沒有徹底理解,只是大概明白了思路,所以導(dǎo)致比賽時遲遲沒有做出這一題,最后現(xiàn)場拿出學(xué)校整理的材料現(xiàn)場重新學(xué)習(xí)才ac的這一題。趁這個機會整理一下常用的字符串處理算法以及模板。

?

字符串處理在比賽中一般都不是特別難(至少我遇到的沒有),有的字符串處理會和dp放在一起出題,加大一些難度,而單純的字符串處理其實還是比較好寫。

?

一、strstr

strstr(str1,str2) 函數(shù)用于判斷字符串str2是否是str1的子串。如果是,則該函數(shù)返回str2在str1中首次出現(xiàn)的地址;否則,返回NULL。據(jù)說strstr的效率和kmp差不多。

strstr沒什么好說的,注意返回的是地址,如果要下標就用返回值減去數(shù)組首地址即可。

例題:http://acm.fzu.edu.cn/problem.php?pid=2128

分析:找出所有子串的位置,排序之后找到相鄰兩個子串的第二個字母與倒數(shù)第二個字母的距離,維護最大即可。

代碼:

#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define MAXN 1000010 using namespace std; char str[MAXN],tmp[105]; struct node{int start,endn; }no[MAXN]; int cnt=0; bool cmp(node a,node b){return a.start<b.start; } int main(){while(~scanf("%s",str)){int n;scanf("%d",&n);cnt=0;int len=strlen(str);int res=-1;while(n--){scanf("%s",tmp);int pos=0;int ltmp=strlen(tmp);while(strstr(str+pos,tmp)!=NULL){int ans=strstr(str+pos,tmp)-str;no[cnt].start=ans;no[cnt].endn=ans+ltmp-1;pos=no[cnt].endn;cnt++;}}no[cnt].start=no[cnt].endn=len;cnt++;sort(no,no+cnt,cmp);/*for(int i=0;i<cnt;i++)cout<<no[i].start<<" "<<no[i].endn<<endl;*/for(int i=0;i<cnt-1;i++)res=no[i+1].endn-no[i].start-1>res?no[i+1].endn-no[i].start-1:res;if(res==-1)printf("%d\n",len);else printf("%d\n",res);} } strstr應(yīng)用

?

二、字符串hash

具體的哈希總結(jié)會另開一專題,這里只貼一下字符串哈希常用的模板:

1.SDBMHash

unsigned int SDBMHash(char *str){unsigned int hash = 0;while (*str){// equivalent to: hash = 65599*hash + (*str++);hash = (*str++) + (hash << 6) + (hash << 16) - hash;}return (hash & 0x7FFFFFFF); }

2.BKDRHash

unsigned int BKDRHash(char *str){unsigned int seed = 131; // 31 131 1313 13131 131313 etc..unsigned int hash = 0;while (*str){hash = hash * seed + (*str++);}return (hash & 0x7FFFFFFF); }

3.APHash

unsigned int APHash(char *str){unsigned int hash = 0;int i;for (i=0; *str; i++){if ((i & 1) == 0){hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));} else{hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));}}return (hash & 0x7FFFFFFF); }

3.kmp

kmp是acm中最常用的字符串處理算法,雖然其效率可能不如Sunday,BM等算法,但是其地位是不容質(zhì)疑的。

kmp算法實質(zhì)是在暴力尋找的基礎(chǔ)上添加了next數(shù)組,其思想就是先對于模式串進行預(yù)處理,然后利用已有的匹配信息,優(yōu)化在查找時候的模式串移動位數(shù)。

舉個例子:

比如主串是:ASDFVAGBASDFGABSDFASDABCBDSFB,模式串是ABCABD。

我們首先從左向右比較,發(fā)現(xiàn)第二位沒有匹配,此時如果是暴力的思想,我們應(yīng)該以主串的第二位為首重新進行匹配,但是其實我們沒有必要這樣做,因為我們可以在主串中找到下一個A開始比較即可。

而我們要做的就是如何利用已知信息去尋找這個next數(shù)組,也就是如何對查詢過程進行優(yōu)化。

由此,我們引出了對于一個字符竄的前后綴概念。前綴是指一個字符串除去最后一個字母并且包含首字母的子串,后綴是指一個字符串除去首字母并且包含尾字母的子串。

舉個例子:

  對于字符串:ABCDABD 來說:

  - "A"的前綴和后綴都為空集,共有元素的長度為0;

  - "AB"的前綴為[A],后綴為[B],共有元素的長度為0;

  - "ABC"的前綴為[A, AB],后綴為[BC, C],共有元素的長度0;

  - "ABCD"的前綴為[A, AB, ABC],后綴為[BCD, CD, D],共有元素的長度為0;

  - "ABCDA"的前綴為[A, AB, ABC, ABCD],后綴為[BCDA, CDA, DA, A],共有元素為"A",長度為1;

  - "ABCDAB"的前綴為[A, AB, ABC, ABCD, ABCDA],后綴為[BCDAB, CDAB, DAB, AB, B],共有元素為"AB",長度為2;

  - "ABCDABD"的前綴為[A, AB, ABC, ABCD, ABCDA, ABCDAB],后綴為[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的長度為0。

其實,我們也可以這樣理解,next數(shù)組中存儲的就是到這一位為止,有多少和從模式串的頭算起相同的位數(shù)。

比如ABCDABD,next[6]==2,就是到第六位為止,對于這個子串存在一個兩位的既存在于前綴中,也存在于后綴中,也就是在串中和模式串首重復(fù)的字串:AB。

而當我們在進行kmp時,模式串向后移動的距離就不簡簡單單是1位,而是“移動位數(shù) = 已匹配的字符數(shù) - 對應(yīng)的部分匹配值”。

比如我們對于模式串ABCDABD來說,此時主串為ABCDABACDABCDABD,模式串的next數(shù)組前面已經(jīng)得到,為0,0,0,0,1,2,0。首先我們匹配到第七位失配,就需要向后移動(已匹配的6位-最后一個匹配位所對應(yīng)的next值2)=4位,這樣就極大的提高了效率。

?

const int MAXN_T=1000010; const int MAXN_P=10010; char P[MAXN_P],T[MAXN_T]; int _next[MAXN_P]; void init_next(char *P){int m=strlen(P+1); //數(shù)組下標從1開始_next[1]=0; //next數(shù)組第一位是0for(int k=0,q=2;q<=m;q++){ //q是模板字符串下標,k是最大前后綴長度while(k>0 && P[k+1]!=P[q]) //遞歸求P串的各位最大相同前后綴長度k=_next[k];if(P[k+1]==P[q]) //如果兩位相等,最大相同前后綴長度加1k++;_next[q]=k;} } 求next數(shù)組模板 int kmp(char *P,char *T){int n=strlen(T+1),m=strlen(P+1);init_next(P);int sum=0;for(int i=1,q=0;i<=n;i++){ //i是T串下標,q是P串下標while(q>0&&P[q+1]!=T[i]) //根據(jù)最大前后綴長度找應(yīng)該向后移動多少位q=_next[q];if(P[q+1]==T[i])q++;if(q==m){ //如果P串匹配到最后一位并且成功sum++; //則計數(shù)加1q=_next[q]; //可以繼續(xù)查詢T串中共出現(xiàn)P串多少次} //如果只查詢是否存在可以直接在這return }return sum; } kmp模板

?

其余關(guān)于字符串處理的算法比如自動機,后綴數(shù)組,BM,Sunday,暫時還沒有太深的了解,等到有了時間和機會,會再來補上!

轉(zhuǎn)載于:https://www.cnblogs.com/Torrance/p/5445946.html

總結(jié)

以上是生活随笔為你收集整理的算法分类整理+模板②:字符串处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。