KMP アルゴリズム (文字列マッチング) (AcWing)

KMP アルゴリズムは文字列のマッチングによく使用されますが、KMP アルゴリズムのマッチングを紹介する前に、まず文字列を激しくマッチングする方法を紹介します。

 2 つの文字列の場合、2 つのポインターを使用して順番に比較します。コードは次のとおりです。

for (int i = 1; i <= n; i ++ )
{
    bool flag = true;
    for (int j = 1; j <= m; j ++ )
    {
        if (s[i + j - 1] != p[j])
        {
            flag=false;
            break;
        }
    }
}

一致しない場合、短い文字列を右に移動して一致を続けるのと同じですが、逐次比較の効率は非常に低くなります

 KMP は、すでに一致した文字列の有効な情報を使用して、重複する一致を減らします。

 例えば、図において、長い文字列と短い文字列が一定区間照合できた場合、図中の位置 i と j+1 の位置で照合が失敗するため、従来の考え方では、短い文字列を移動する必要があります。 1つ後ろに戻って再度マッチングを開始しますが、kmpはマッチング情報を有効活用してマッチング数を減らすため、つまりj=ne[j]とし、ne[の位置からマッチングを開始します。 j] ですが、実際には図の黒線で描いた部分が に等しいので有効なので、この部分を一致させる必要はありません。 では、この ne[j] 配列を見つけるにはどうすればよいでしょうか?

ここで導入する概念、つまりprefixsuffix を示します

 アイデアは理解できたので、それをコードで実装するにはどうすればよいでしょうか?

アイデア:

 コード:

	for (int i = 2, j = 0; i <= m; i++)
	{
		while (j && str1[i] != str1[j + 1])j = ne[j];
		if (str1[j + 1] == str1[i])j++;
	    ne[i] = j;
	}

次に、サンプルをシミュレートしてみましょう。

 トピック:

ACコード:

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1000010, M = 10010;
char str[N], str1[M];
int ne[N], n, m;

int main(void)
{
	cin >>(str + 1) >>(str1 + 1);
	int n = strlen(str+1), m = strlen(str1+1);
	//获取ne数组
	for (int i = 2, j = 0; i <= m; i++)
	{
		while (j && str1[i] != str1[j + 1])j = ne[j];
		if (str1[j + 1] == str1[i])j++;
		ne[i] = j;
	}
	//开始匹配
	for (int i = 1, j = 0; i <= n; i++)
	{
		while (j && str1[j + 1] != str[i])j = ne[j];
		if (str[i] == str1[j + 1])j++;
		if (j == m)
		{
			printf("%d\n", i - m+1);
		}
	}
	for (int i = 1; i <= m; i++)
	{
		printf("%d ", ne[i]);
	}
	return 0;
}

おすすめ

転載: blog.csdn.net/AkieMo/article/details/128434277