字符串匹配有传统的BF(brute force)方法,时间复杂度O(m * n)。
KMP算法的时间复杂度为O(m + n),利用匹配字串的规律,建立一个next数组,记录的是当前字符匹配错误时回溯到的字符下标。
具体内容参见:字符串匹配的KMP算法
当然kmp算法不一定仅限于字符串,只要有字符串的特性就可以。
留份模板:
int Next[M];
void getnext(char str[]) {
int i = 0, j = -1, len = strlen(str);
Next[0] = -1;
while(i < len) {
if(j == -1 || str[j] == str[i]) {
j++;i++;
Next[i] = j;
}
else j = Next[j];
}
}
int kmp(char str1[], char str2[]){// 模式串 母串
int i = 0, j = 0, len1 = strlen(str1), len2 = strlen(str2);
while(i < len2) {
if(str2[i] == str1[j] || j == -1) j++, i++;
else j = Next[j];
if(j == len1) return i - len1 + 1;
}
return -1;
}
</pre><p>题目:</p><p>hdoj : <a target=_blank target="_blank" href="http://acm.hdu.edu.cn/showproblem.php?pid=1711">http://acm.hdu.edu.cn/showproblem.php?pid=1711</a></p><p>思路:</p><p>kmp裸题。</p><p>AC代码:</p><p></p><pre code_snippet_id="371196" snippet_file_name="blog_20140531_1_2636428" name="code" class="cpp">#include<cstdio>
const int M = 1e6 + 20;
int n, m, a[M], b[M], next[M];
void getnext()
{
int i = 0, j = -1;
next[0] = -1;
while(i < m)
{
if(j == -1 || b[j] == b[i])
{
j++;i++;
next[i] = j;
}
else
j = next[j];
}
}
int kmp()
{
getnext();
int i = 0, j = 0;
while(i < n)
{
if(a[i] == b[j] || j == -1)
j++, i++;
else
j = next[j];
if(j == m)
return i - m + 1;
}
return -1;
}
main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
scanf("%d", &a[i]);
for(int i = 0; i < m; i++)
scanf("%d", &b[i]);
int flag = kmp();
if(flag == -1)
puts("-1");
else
printf("%d\n", flag);
}
}
题目:
hdoj : http://acm.hdu.edu.cn/showproblem.php?pid=3336
思路:
KMP算法的变种,先预处理next数组,然后用滚动数组,记录各个前缀串被重复记录了多少次,累加。
AC代码:
#include<cstdio>
#include<cstring>
const int M = 2e5 + 20;
const int MOD = 1e4 + 7;
int n, next[M], dp[M];
char str[M];
void getnext()
{
int i = 0, j = -1;
next[0] = -1;
while(i < n)
{
if(j == -1 || str[j] == str[i])
{
j++;i++;
next[i] = j;
}
else
j = next[j];
}
}
main()
{
int t;
scanf("%d", &t);
while(t--)
{
memset(dp, 0, sizeof(dp));
scanf("%d", &n);
scanf("%s", str);
getnext();
int ans = 0;
for(int i = 1; i <= n; i++)
{
dp[i] = dp[next[i]] + 1;//dp[i]是当以i为结束点时,有多少前缀匹配。如abab dp[1] = 1, dp[2] = 1, dp[3] = 2, dp[4] = 2
dp[i] = dp[i] % MOD;
ans += dp[i];
ans = ans % MOD;
}
printf("%d\n", ans);
}
}