实用算法实践-第 22 篇 字符串匹配

22.1    Knuth-Morris-Pratt算法

22.1.1   实例

PKU JudgeOnline, 3461, Oulipo.

22.1.2   问题描述

求字符串在另外一个字符串中出现了几次。

22.1.3   输入

3

BAPC

BAPC

AZA

AZAZAZA

VERDI

AVERDXIVYERDIAN

22.1.4   输出

1

3

0

22.1.5   分析

标准的KMP算法解决的问题。将KMP的伪代码一翻译就出来了。

22.1.6   程序

#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int count;
char W[100002];
char T[1000002];
int prefix[1000002];
void computePrefix(char* P, int* prefix)
{
     int m;
     int k;
     int q;
     m = strlen(P) - 1;
     prefix[1] = 0;
     k = 0;
     for(q = 2;q <= m; q++){
         while(k> 0 && P[k + 1] != P[q]){
              k = prefix[k];
         }
         if(P[k+ 1] == P[q])
         {
              k = k + 1;
         }
         prefix[q] = k;
     }
}
void KMP_matcher(char* T, char* P){
     int n;
     int m;
     int q;
     int i;
     n = strlen(T) - 1;
     m = strlen(P) - 1;
     computePrefix(P, prefix);
     q = 0;
     for(i = 1;i <= n; i++){
         while(q> 0 && P[q + 1] != T[i]){
              q = prefix[q];
         }
         if(P[q+ 1] == T[i])
         {
              q = q + 1;
         }
         if(q ==m)
         {
              count ++;
              q = prefix[q];
         }
     }
}
int main()
{
     int time;
     cin >> time;
     for(; time> 0; time--){
         count = 0;
         scanf("%s",&W[1]);
         W[0] = '@';  
         scanf("%s",&T[1]);
         T[0] = '@';
         KMP_matcher(T, W);
         cout << count << endl;
     }
     return 1;
}

22.2    Knuth-Morris-Pratt算法的前缀函数的应用

22.2.1   实例

PKU JudgeOnline, 2752, Seek the Name, Seek the Fame.

22.2.2   问题描述

输出一个字符串中所有前缀、后缀相等的长度。

22.2.3   输入

ababcababababcabab

aaaaa

22.2.4   输出

24 9 18

12 3 4 5

22.2.5   分析

该题的题意是这样的,给若干个字符串,判断该字符串前n个字符和后n个字符是否相同,按从小到大的顺序输出n,比如,给ababab,结果输出2 4 6,再比如ababcababababcabab 输出 2 4 9 18。

我们要根据kmp算法中的next函数来解决这个问题,以ababab为例加以说明:

String:ababab

Next: 0112345

这里根据后面的需要多计算了一位next值。

我们用ababab即作为主串有作为模式串来进行匹配,假设匹配到第7位时不匹配了(下标中1开始),要根据next[7](=5)的值继续匹配:

ababab*

ababab&

ababab*

 ababab

可以由5得出4(5-1)是符合要求的,然后求next[5]=3,即继续这样匹配:

ababab*

 ababab

可以由5得出2(3-1)是符合要求的,然后求next[3]=1,停止循环。

这样,我们依此输出2 4 6即可。

22.2.6   程序

#include <iostream.h>

#include <string.h>

#include <stdlib.h>

#include <stdio.h>

void computePrefix(char* P, int* prefix)

{

     int m;

     int k;

     int q;

     m = strlen(P) - 1;

//   cout <<"m:" << m <<endl;

     prefix[1] = 0;

     k = 0;

//   cout <<prefix[1] << " ";

     for(q = 2;q <= m; q++){

         while(k> 0 && P[k + 1] != P[q]){

              k = prefix[k];

         }

         if(P[k+ 1] == P[q])

         {

              k = k + 1;

         }

         prefix[q] = k;

     //   cout << prefix[q] << "";

     }

     //cout  << endl;

}

char S[400002];

int prefix[400002];

int result[400002];

int main()

{

     int j,index, length;

     while(scanf("%s", &S[1]) != EOF){

         S[0] = '@';

         computePrefix(S, prefix);

         length = strlen(S) - 1;

         j = length;

         index = 0;

         while(1)

         {

              j = prefix[j];

              if(j== 0)

                   break;

              result[++index] = j;

         }

         for(;index > 0; index-- ){

              printf("%d", result[index]);

         }

         cout << length << endl;

     }

     return 1;

}

22.3    实例

PKU JudgeOnline, 2752, Seek the Name, Seek the Fame.

PKU JudgeOnline, 1961, Period.

PKU JudgeOnline, 2406, Power Strings.

PKU JudgeOnline, 3461, Oulipo.

本文章欢迎转载,请保留原始博客链接http://blog.csdn.net/fsdev/article

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值