KMP算法 2203 親和串

kmp算法

背景:已知字符串a和字符串b,求字符串b在字符串a中首次出現的位置

kmp算法的核心精髓在於求next數組

next數組含義:next[i] 以 i 結尾(不包括 i)的字符串中前綴和後綴最長相等的長度

比如:s = aabcdaabcd

前綴:a、aa、aab、aabc、aabcd ....... aabcdaabc 都是 s 的前綴

後綴:d、cd、bcd、abcd、aabcd ....... aabcdaabc 都是 s 的後綴

next 數組中 next[0] = -1 這個是一定的,可以看做是規定吧

s的next 數組爲

i           0  1  2  3  4  5  6  7  8  9

s          a  a  b  c  d  a  a  b  c  d  

next    -1  0  1  0  0  0  1  2  3  4

就比如說 next[8] 的求法:

以8結尾的字符串爲 aabcdaab,我們一眼就可以看出前綴和後綴的最長相等長度爲3,即aab和aab,如何讓計算機自己求呢?

求next[8]的時候,next[0]~next[7]都是已知的,那麼我們可以利用next[7]的結果

以7結尾的字符串爲aabcdaa,next[7]=2,那麼求next[8]時可以直接判斷s[7]是否等於s[next[2]]就好了,如果相等,那麼next[8]=next[7]+1,如果不相等,那麼就要在判斷s[7]是否等於s[next[2]],繼續下去,直到相等或者到next[0]=-1了,就跳出循環。

這個表達的也許不是很清楚,光看也不可能看懂,也許還是會有一些不動,一邊動手,一邊摸索明白可以更好地理解。總之一定要記得next數組的含義

求得了next數組,接下來就是要匹配了

比如 a = aabcdaabcd  i=0,指向a字符串

        b = cdaa              j=0,指向b字符串

先是一位一位的判斷是否相等,如果相等那麼i++、j++

                                                         不相等那麼j = next[j],繼續判斷,爲什麼可以這樣呢,因爲在第 j 位失配(沒有匹配),那說明字符串b從0~j-1和字符串a從i-j~i-1相等,而next[j]=k表示字符串b中0~k-1 和 j-k~j-1 是相等的,那麼字符串a從i-j~i-1和0~k-1是相等的,即只要比較a[i]==b[next[j]]是否爲true就好

KMP算法的思路就是這樣了


思路明白了,多寫幾道題吧,邊寫邊熟悉,直到自己會了

hdu 2203一道挺水的題,適合學會了KMP算法來寫,基本上就是套模板了

親和串


Problem Description
人隨着歲數的增長是越大越聰明還是越大越笨,這是一個值得全世界科學家思考的問題,同樣的問題Eddy也一直在思考,因爲他在很小的時候就知道親和串如何判斷了,但是發現,現在長大了卻不知道怎麼去判斷親和串了,於是他只好又再一次來請教聰明且樂於助人的你來解決這個問題。
親和串的定義是這樣的:給定兩個字符串s1和s2,如果能通過s1循環移位,使s2包含在s1中,那麼我們就說s2 是s1的親和串。
 

Input
本題有多組測試數據,每組數據的第一行包含輸入字符串s1,第二行包含輸入字符串s2,s1與s2的長度均小於100000。
 

Output
如果s2是s1的親和串,則輸出"yes",反之,輸出"no"。每組測試的輸出佔一行。
 

Sample Input
AABCD CDAA ASD ASDF
 

Sample Output
yes no
 
題目爲中文,看一眼就明白題目的意思,思路就是把s1+=s1,然後用kmp算法的模板就ok了

<span style="font-size:18px;">#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn = 100000+5;
int Next[maxn];
void getNext(string s)
{
    Next[0]=-1;
    Next[1]=0;
    int ls=s.size();
    for(int i=2;i<ls;i++){
        if(s[i-1]==s[Next[i-1]]) Next[i]=Next[i-1]+1;
        else{
            int t=Next[i-1];
            while(s[t]!=s[i-1]){
                t=Next[t];
                if(t==-1) break;
            }
            Next[i]=t+1;
        }
    }
}
int kmp(string s1,string s2)
{
    int ls1=s1.size();
    int ls2=s2.size();
    int i=0,j=0;
    while(i<ls1 && j<ls2){
        if(s1[i]==s2[j]) i++,j++;
        else{
            //j=Next[j];
            while(s1[i]!=s2[j]){
                j=Next[j];
                if(j==-1){
                    i++;
                    j++;
                    break;
                }
            }
        }
        if(j==ls2) return i-ls2;
    }
    return -1;
}
int main()
{
    string s1,s2;
    int ans;
    while(cin>>s1>>s2){
        getNext(s2);
        //for(int i=0;i<s2.size();i++) cout<<Next[i]<<' ';cout<<endl;
        s1+=s1;
        ans=kmp(s1,s2);
        //cout<<"ans="<<ans<<endl;
        if(ans==-1) cout<<"no"<<endl;
        else cout<<"yes"<<endl;
    }
    return 0;
}
</span>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章