KMP模版 && KMP求子串在主串出现的次数模版
求取出现的次数 :
#include<bits/stdc++.h> const int maxn = 1e6 + 10; char mo[maxn], str[maxn];///mo为模式串、str为主串 int next[maxn]; inline void GetNext() { int i = 0, j = -1, len = strlen(mo); next[i] = j; while(i < len){ // if(j == -1 || mo[i] == mo[j]) next[++i] = ++j; // else j = next[j]; while( j != -1 && mo[i] != mo[j]) j = next[j]; next[++i] = ++j; } } int KmpCount()///计算模式串在子串出现的次数 { GetNext(); int i = 0, j = 0, strL = strlen(str), moL = strlen(mo); int ans = 0; while(i < strL){ while( j != -1 && mo[j] != str[i]) j = next[j]; i++, j++; if(j == moL) ans++; } return ans;///返回模式串在主串中出现的次数(可重叠出现) } int main(void) { scanf("%s %s", str, mo); printf("%d\n", KmpCount()); return 0; }
求模式串第一次在主串出现的位置 or 匹配是否在主串出现过 :
#include<bits/stdc++.h> const int maxn = 1e6 + 10; char mo[maxn], str[maxn];///mo为模式串、str为主串 int next[maxn]; inline void GetNext() { int i = 0, j = -1, len = strlen(mo); next[i] = j; while(i < len){ while( j != -1 && mo[i] != mo[j]) j = next[j]; next[++i] = ++j; } } int KmpIndex() { GetNext(); int i =0, j = 0, strL = strlen(str), moL = strlen(mo); while(i < strL && j < moL){ while( j != -1 && str[i] != mo[j]) j = next[j]; i++, j++; } if(j == moL) return i - moL;///返回模式串在主串中首次出现的位置 else return -1; } int main(void) { scanf("%s %s", str, mo); printf("%d\n", KmpIndex()); return 0; }
///--------------------------------------------------------------------------------------------------------------------------
KMP算法的解释尤其是next数组可以参考这个博客 : http://blog.csdn.net/yutianzuijin/article/details/11954939/
这个是我对KMP的next数组的一点理解,都写在注释里面了
#include<bits/stdc++.h> const int maxn = 1e6 + 10; char mo[maxn], str[maxn];///分别为模式串和子串 int next[maxn]; /// next[i] 可以"翻译"成 i 这里失配了,考虑 0~(i-1) 这个 /// 串,看能否找到一个位置 k 和 k' 使得前缀 0~k 和后缀 /// k'~(i-1)一样,而next[i]存储的就是 k+1 这个位置,即 /// 前缀的前一个 inline void GetNext() { int i = 0, j = -1, len = strlen(mo); next[i] = j; while(i < len){ while( j != -1 && mo[i] != mo[j]) j = next[j]; next[++i] = ++j; } } ///------------------------------------------------------------- ///可以用下面的图来动态演示一下GetNext()的步骤,可能就能够理解 // i //- 0 1 2 3 4 5 6 7 8 // a b c a b c a d x // - 0 0 0 1 2 3 4 0 // a b c a b c a d x // - 0 0 0 1 2 3 4 0 // j ///下面有几句话可能能帮助理解 ///①找next的值相当于就是拿模式串自己和自己匹配,在下面移动的就是后缀,在上面的就是前缀 ///②当前匹配的字符以及其前面的字符的next值肯定是已经求出来的 ///③当j==-1的时候就说明现在的i连模式串的第一个都不能匹配到 ///④如果是判断当前的 i 和 j 则说明是在为 i+1 这个字符寻找 0~i (即i+1后的字符串)是否拥有相同前后缀 ///-------------------------------------------------------------- int KmpCount() { GetNext(); int i = 0, j = 0, strL = strlen(str), moL = strlen(mo); int ans = 0; while(i < strL){ while( j != -1 && mo[j] != str[i]) j = next[j];///匹配的时候当 j == -1 的时候就已经是第 i++, j++; ///一个现在的主串 i 连模式串的第一个都不 if(j == moL) ans++; ///能匹配,所以下面让 i++,因为 j == -1, } ///所以 j++ 后自然是子串第一个 return ans; }