1. 程式人生 > 其它 >LeetCode 62. 不同路徑

LeetCode 62. 不同路徑

KMP可以解決什麼問題

如何在一個字串中查詢一個目標字串B是否出現在A中?

方法:暴力,用雙重迴圈,時間複雜度\(O(N\times M)\)

KMP原理詳解

暴力實在是太慢了!!!

我們可以先想一下,暴力演算法慢在哪裡

我們考慮如何加速

我們就進行了優化,首先我們預處理出一個表

然後就在匹配的時候如果成功,就\(i++,j++\)否則就\(j=next[j]\)

於是這就可以快速匹配了。

KMP實現

求出\(next\)陣列的關鍵就是目標自己匹配自己。

我們用一個累加器來統計,如果匹配成功的話就繼續,同時累加器++,否則就累加器清零,然後\(j\)指標回到\(0\),重新giao一下就好了。

如果我們搞好了,我們就直接無腦匹配就可以了。

Code:

#include<iostream>
#include<string> 
using namespace std;
int nxt[1000005];
int len1, len2;

void getNext(string s2) //求nxt陣列, 把目標串s2當作主串,把s2的字首當作目標串進行匹配 
{
    nxt[0] = -1; //-1並沒有特殊的意義,下標跳到-1說明目標串第一個字元就跟主串不匹配 
    int i = 0, j = -1; // i表示最長公共字尾的末位下標, j表示最長公共字首的末尾下標 
    while(i < len2)
    {
        if(j == -1 || s2[i] == s2[j])  
        {
            i++;
            j++;
            nxt[i] = j;
        }
        else //當前綴與字尾的末尾下標不匹配時,字首的末位下標跳轉至 
        {
            j = nxt[j];  
        }
    }
    return ;
}

void KMP(string s1, string s2) //匹配函式,輸出s2在s1中出現的下標 
{
    getNext(s2); //nxt陣列 
    int i = 0, j = 0; //i表示s1的下標, j表示s2的下標 
    while(i < len1)
    {
        if(j == len2 - 1 && s1[i] == s2[j]) //找到目標串 
        {
            cout << i - j + 1 << endl; //輸出目標串在s1中出現的起始位置 ,題目下標從1開始 
            j = nxt[j];
        }
        if(j == -1 || s1[i] == s2[j]) //j == -1目標串第一個字元就不匹配,跟主串的下一個字元開始匹配 
        {
            i++;
            j++;
        }
        else //失配 
        {
            j = nxt[j]; 
        }
    }
    return;
} 

int main()
{
    string s1, s2;
    cin >> s1 >> s2;
    len1 = s1.size();
    len2 = s2.size();
    KMP(s1, s2);
    for(int i = 1; i <= len2; i++) //P3375要求的是沒有右移過的nxt陣列,所以直接從下標1開始輸出 
    {
        cout << nxt[i] << " ";
    }
    return 0;
}