KMP算法

来源:互联网 发布:c语言计算器程序代码 编辑:程序博客网 时间:2024/05/18 02:45

1、KMP算法由来

字符串匹配问题描述:参见 

LeetCode OJ:Implement strStr()

关于这个问题,最简单的想法就是扫描字符串s,一个一个进行比对,具体实现参见问题解答

2、简单匹配算法,BF算法,思想较简单,不做解释

class Solution {  public:      int BF(char *S ,char *T) {                    int slen = strlen(S);          int tlen = strlen(T);          int i = 0 ,j = 0;                    while ( i+j < slen && j < tlen){              if ( S[i+j] == T[j] ){                  j ++;              }              else              {                  i ++;                  j = 0;              }          }          if ( j >= tlen)              return i;          else              return -1;      }  };  


3、KMP算法

(1)由来:

因为BF算法时间复杂度为O(M*N),每一次不匹配后都需要跳回S字符串的下一个字符出进行

举个例子,假设T字符串中的字符两两不同,那么当循环到某一位置不匹配时,压根就不需要回到S的下一个i位置处进行,直接从当前位置处向后循环比对就可以了,因为T字符串两两不同,前面的字符根本不可能作为第一个匹配的字符,    所以,从这来看,可以设计这样一种算法,该算法时间复杂度取决于T字符串中相同字符的个数,因此,KMP算法应运而生。时间复杂度可提高为O(M+N)

(2)模式值next[n]

简单地说,模式值next[n]就是当字符串不匹配时,不是回到字符串的起点,而是回到某个位置,next[n]记录第n位置元素不匹配时应该反回到的位置,然后向后进行匹配

(3)next[n]函数

至此,主要问题归结于求模式值next[n]

定义

1next[0]= -1  意义:任何串的第一个字符的模式值规定为-1

2next[j]= -1   意义:模式串T中下标为j的字符,如果与首字符相同,且j的前面的1—k个字符与开头的1—k个字符不等(或者相等但T[k]==T[j])(1k<j)。

如:T=”abCabCad”  next[6]=-1,因T[3]=T[6]

3next[j]=k    意义:模式串T中下标为j的字符,如果j的前面k个字符与开头的k个字符相等,且T[j] != T[k] 1k<j)。

                       T[0]T[1]T[2]。。。T[k-1]==T[j-k]T[j-k+1]T[j-k+2]…T[j-1]T[j] != T[k].1k<j;

(4) next[j]=0   意义:除(1)(2)(3)的其他情况。

举例

01)求T=abcac”的模式函数的值。

     next[0]= -1  根据(1

     next[1]=0   根据 (4)   因(3)有1<=k<j;不能说,j=1,T[j-1]==T[0]

     next[2]=0   根据 (4)   因(3)有1<=k<j;T[0]=a!=T[1]=b

     next[3]= -1  根据 (2)

     next[4]=1   根据 (3)  T[0]=T[3]  T[1]=T[4]

       

下标

0

1

2

3

4

T

a

b

c

a

c

next

-1

0

0

-1

1

T=abcab”将是这样:

下标

0

1

2

3

4

T

a

b

c

a

b

next

-1

0

0

-1

0

为什么T[0]==T[3],还会有next[4]=0因为T[1]==T[4], 根据 (3)” T[j] != T[k]”被划入(4)。

02)来个复杂点的,求T=”ababcaabc” 的模式函数的值。

next[0]= -1    根据(1

         next[1]=0    根据(4)

         next[2]=-1   根据 (2)

next[3]=0   根据 (3) T[0]=T[2] T[1]=T[3] 被划入(4

next[4]=2   根据 (3) T[0]T[1]=T[2]T[3] T[2] !=T[4]

next[5]=-1  根据 (2) 

next[6]=1   根据 (3) T[0]=T[5] T[1]!=T[6]

next[7]=0   根据 (3) T[0]=T[6] T[1]=T[7] 被划入(4

next[8]=2   根据 (3) T[0]T[1]=T[6]T[7] T[2] !=T[8]

 

下标

0

1

2

3

4

5

6

7

8

T

a

b

a

b

c

a

a

b

c

next

-1

0

-1

0

2

-1

1

0

2

只要理解了next[3]=0,而不是=1next[6]=1,而不是= -1next[8]=2,而不是= 0,其他的好象都容易理解。

03)   来个特殊的,求 T=”abCabCad” 的模式函数的值。

下标

0

1

2

3

4

5

6

7

T

a

b

C

a

b

C

a

d

next

-1

0

0

-1

0

0

-1

4

         

next[5]= 0  根据 (3) T[0]T[1]=T[3]T[4],T[2]==T[5]

next[6]= -1  根据 (2) 虽前面有abC=abC,T[3]==T[6]

next[7]=4   根据 (3) 前面有abCa=abCa, T[4]!=T[7]

T[4]==T[7],即T=” adCadCad”,那么将是这样:next[7]=0, 而不是= 4,因为T[4]==T[7].

下标

0

1

2

3

4

5

6

7

T

a

d

C

a

d

C

a

d

next

-1

0

0

-1

0

0

-1

0

 

意义

 next 函数值究竟是什么含义,前面说过一些,这里总结。

设在字符串S中查找模式串T,若S[m]!=T[n],那么,取T[n]的模式函数值next[n],

1.       next[n]=  -1 表示S[m]T[0]间接比较过了,不相等,下一次比较 S[m+1]T[0]

2.       next[n]=0 表示比较过程中产生了不相等,下一次比较 S[m] T[0]

3.       next[n]= k >0 k<n, 表示,S[m]的前k个字符与T中的开始k个字符已经间接比较相等了,下一次比较S[m]T[k]相等吗?

4.       其他值,不可能。

所以next[n]函数为

void get_nextval(char const* ptrn, int plen, int* nextval)          {              int i = 0;               nextval[i] = -1;              int j = -1;              while( i < plen-1 )              {                  if( j == -1 || ptrn[i] == ptrn[j] )                  {                      ++i;                      ++j;                                           if( ptrn[i] != ptrn[j] )                           nextval[i] = j;                            else                          nextval[i] = nextval[j];                  }                  else                                                       j = nextval[j];              }          }  

当next[n]生成后,其他的和BF就一样了,j=0换成j=nextval[j]而已

class Solution {  public:            void get_nextval(char const* ptrn, int plen, int* nextval)          {              int i = 0;               nextval[i] = -1;              int j = -1;              while( i < plen-1 )              {                  if( j == -1 || ptrn[i] == ptrn[j] )                 {                      ++i;                      ++j;                                           if( ptrn[i] != ptrn[j] )                           nextval[i] = j;                            else                          nextval[i] = nextval[j];                  }                  else                                                       j = nextval[j];              }          }      int KMP(char *S, char *T) {                    int slen = strlen(S);          int tlen = strlen(T);          int i = 0 ,j = 0;                    int *nextval=new int[tlen];          get_nextval(T,tlen,nextval);                    while ( i+j < slen && j < tlen){              if ( j == -1 || S[i+j] == T[j] ){                  j ++;              }              else              {                  i ++;                  j = nextval[j];              }          }          if ( j >= tlen)              return i;          else              return -1;      }  };  


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小孩学过就忘了怎么办 做事老是注意力不集中怎么办 做事无法专注注意力不集中怎么办 幼儿园孩子上课不认真听讲怎么办 孩子在课间打闹家长应该怎么办 孩子打闹家长额钱怎么办 我又打孩子了怎么办 打排卵针不排卵怎么办 总是控制不住打骂孩子怎么办 叛逆期的孩子打骂妈妈怎么办 孩子屁股打青了怎么办 父亲把孩子屁股打流血怎么办 孩子屁股长了湿疹怎么办 宝宝发脾气摔东西躺地上怎么办 生气拿棍子打了孩子怎么办 小宝宝被蚊虫咬了怎么办 小宝宝被蚊子咬了怎么办 衣架打小孩淤青怎么办 1岁宝宝有痰咳嗽怎么办 1岁宝宝咳嗽有痰怎么办 孩子爱动手打家长怎么办 不小心有了孩子该怎么办 2岁多宝宝干咳怎么办 2岁宝宝咳嗽无痰怎么办 打了孩子后悔了怎么办 12小孩脾气很犟怎么办 被学生气着了怎么办 1岁宝宝轻微咳嗽怎么办 4岁宝宝突然呕吐怎么办 4岁儿童突然呕吐怎么办 四岁儿童90身高怎么办 24个月宝宝缺钙怎么办 狗狗总是要人陪着玩怎么办 成年了还是很皮怎么办 三岁儿子太调皮怎么办 10个月宝宝粘人怎么办 6个月宝宝粘人怎么办 9个月宝宝偏矮怎么办 1岁宝宝粘人爱哭怎么办 宝宝2岁半胆小怎么办 5岁宝宝超级粘人怎么办