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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

嫦娥奔月(KMP,找循环节)及其扩展KMP

發布時間:2025/4/16 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嫦娥奔月(KMP,找循环节)及其扩展KMP 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

問題描述

《歸妹》卦辭為:昔者恒我(姮娥)竊毋死之藥于西王母,服之以(奔)月。將往,而枚占于有黃。有黃占之曰:“吉。翩翩歸妹,獨將西行。逢天晦芒,毋驚毋恐,后且大昌”。恒我遂托身于月,是為蟾蠩。

嫦娥去了廣寒宮以后每天特別無聊,只有小兔子陪她玩。有一天,天蓬元帥來找她去東海玩,雖然她很想出去玩,可是她是后羿的妻子啊,心里又喜歡吳剛,更何況玉帝還在那盯著呢,怎么可以隨隨便便和他出去呢?于是她出了一道題給天蓬,答應只要他做出來了就隨他一起去東海。

題目如下:

1.對于一個字符串S,定義以下n個字符串,S[i]表示一個這樣的字符串:截取S的前i個字符,讓截取部分的第一個字符接在剩下部分的最后一個字符后面。例:對于字符串S =“abcdef”,S[2]表示字符串“cdefab”。

2.將n個字符串進行分組,相同字符串為一組。

3.定義序列L,表示為每一組的字符串的編號按從小到大排列的序列。

4.按照L的字典序從小到大輸出所有分組。

例:S =“abab”,S[0] =“abab”,S[1] =“baba”,S[2] =“abab”,S[3] =“baba”。分組L[]為(0, 2),(1, 3)。對L數組排序后:L[1]=(0, 2),L[2]=(1, 3)。因為0比1小。

這題太難了,為了成功的約到嫦娥,天蓬找到了你來幫忙,你能幫幫他嗎?

輸入描述

輸入包含一個字符串S。

1?≤?|S|?≤?1000000。

S只包含小寫字母。

輸出描述

第一行輸出一個整數K,表示分組個數。

接著K行,每行第一個整數n表示該分組有多少個字符串,后面接著n個整數,表示該分組的字符串的編號。

樣例輸入

ababdeadbeef

樣例輸出

2 2 0 2 2 1 38 1 0 1 1 1 2 1 3 1 4 1 5 1 6 1 7

這道題,我一開始直接模擬去求解,用了一個map,一個multimap和一個set來求解。遍歷一遍,用set將每一次截取后重新拼接的字符串存在set容器中,同時用map計數每一個字符串出現的次數。再用multimap將每一次的截取位置保存下來。然后遍歷一遍輸出。(但卻爆內存了 )

附錯誤代碼(爆內存)

#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<set> #include<map> #include<queue> #include<vector> #include<algorithm>using namespace std;const int maxn = 1e6+5; int main() {string s;map<string, int>m;multimap<string, int>mm;set<string>S;while(cin >> s){for(int i = 0; i < s.length(); i++){string temp = s.substr(i, s.length()-i) + s.substr(0, i);S.insert(temp);m[temp]++;mm.insert(make_pair(temp, i));}map<string, int>::iterator it1;multimap<string, int>::iterator it2;cout << S.size() << endl;for(it1 = m.begin(); it1 != m.end(); it1++){cout <<(*it1).second << " ";for(it2 = mm.begin(); it2 != mm.end(); it2++){if((*it1).first == (*it2).first) cout << (*it2).second << " ";}cout << endl;}m.clear(); mm.clear(); S.clear(); } return 0; }

?

后來看了題解才知道,原來這道題可以用KMP,找循環節來做。

首先我們可以用求解一個長度為n的字符串的next數組,從而找到字符串的循環節cir,那么該字符串就有cir組,每組有n/cir個字符。每次輸出字符編號從0開始。

?

關于KMP的相關知識:KMP詳解

?

ac代碼

#include<cstdio> #include<iostream> #include<cstring> #include<string>using namespace std;const int maxn = 1e6+5; int nxt[maxn]; char str[maxn];void getNext(char str[]){int t = strlen(str);nxt[0] = -1;int j = 0;int k = -1;while(j < t){if(k == -1||str[j] == str[k]) nxt[++j] = ++k;else k = nxt[k];} }int main() {while(scanf("%s", str) != EOF){getNext(str);int t = strlen(str);int cir = t - nxt[t]; //循環節if(t%cir) cir = t;printf("%d\n", cir);int num = t/cir; //有多少組for(int j = 0; j < cir; j++){printf("%d",num);for(int k = j; k < t; k += cir){printf(" %d", k);} printf("\n");}}return 0; }

?

擴展KMP(求原串S1的每一個后綴子串與模式串S2的最長公共前綴長度)es[]數組去存

const int maxn=100010; //字符串長度最大值 int next[maxn],ex[maxn]; //ex數組即為extend數組 //預處理計算next數組 void GETNEXT(char *str) {int i=0,j,po,len=strlen(str);next[0]=len;//初始化next[0]while(str[i]==str[i+1]&&i+1<len)//計算next[1]i++;next[1]=i;po=1;//初始化po的位置for(i=2;i<len;i++){if(next[i-po]+i<next[po]+po)//第一種情況,可以直接得到next[i]的值next[i]=next[i-po];else//第二種情況,要繼續匹配才能得到next[i]的值{j=next[po]+po-i;if(j<0)j=0;//如果i>po+next[po],則要從頭開始匹配while(i+j<len&&str[j]==str[j+i])//計算next[i]j++;next[i]=j;po=i;//更新po的位置}} } //計算extend數組 void EXKMP(char *s1,char *s2) {int i=0,j,po,len=strlen(s1),l2=strlen(s2);GETNEXT(s2);//計算子串的next數組while(s1[i]==s2[i]&&i<l2&&i<len)//計算ex[0]i++;ex[0]=i;po=0;//初始化po的位置for(i=1;i<len;i++){if(next[i-po]+i<ex[po]+po)//第一種情況,直接可以得到ex[i]的值ex[i]=next[i-po];else//第二種情況,要繼續匹配才能得到ex[i]的值{j=ex[po]+po-i;if(j<0)j=0;//如果i>ex[po]+po則要從頭開始匹配while(i+j<len&&j<l2&&s1[j+i]==s2[j])//計算ex[i]j++;ex[i]=j;po=i;//更新po的位置}} }

?

總結

以上是生活随笔為你收集整理的嫦娥奔月(KMP,找循环节)及其扩展KMP的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。