kmp

来源:互联网 发布:程序员游戏 编辑:程序博客网 时间:2024/06/09 00:32

kmp是一种字符串匹配算法,假设主串为s,长度为n,模式串为p,长度为m,则简单模式匹配算法最槽糕的情况下时间复杂度为O(m*n),因为s的指针在匹配会进行回溯,而kmp算法提供了一种s指针只增不减的算法,可以保证最坏时间复杂度为O(n+m)。假设主串s的当前指针为i,模式串p当前指针为j,基本思路为

1.若s[i] == p[j],则i++,j++,与简单模式匹配相同

2.若不相等,则根据next数组对j进行回溯

3.若j增长到m,则存在匹配


kmp的核心是如何保持i不变,而对j进行回溯,即next数组的求解,依据的是前缀和后缀相等的最大长度,主要思路为

1.若k == 0,则next[k] = -1

2.假设next[k] == num ,若p[k] = p[num],则p[k+1] = num+1

3.假设next[k] == num ,若p[k] != p[num] ,则将num置为next[num]继续比较

void GetNext(char *p, int *next){int i = 0, j = -1;next[0] = -1;int m = strlen(p);while(i < m){if(j == -1 || p[i] == p[j])next[++i] = ++j;elsej = next[j];}}

...aaac...
   aaaa.
p串中的'a'和S串中的'c'失配,而'a'的next值指的还是'a',那同样的比较还是会失配,而这样的比较是多余的,如果我事先知道,当 T[i]==T[j],那next[i]就设为next[j],在求next值的时候就已经比较了,这样就可以去掉这样的多余的比较。于是稍加改进得到:

void GetNext(char *p, int *next){int i = 0, j = -1;next[0] = -1;int m = strlen(p);while(i < m){if(j == -1 || p[i] == p[j]){if(p[++i] == p[++j])next[i] = next[j];elsenext[i] = j;}elsej = next[j];}}
下面是两种next数组的举例(1是改进版):

下标

0

1

2

3

4

5

6

7

8

T

a

b

a

b

c

a

a

b

c

(1) next

-1

0

-1

0

2

-1

1

0

2

(2) next

-1

0

0

1

2

0

1

1

2


下标

0

1

2

3

4

T

a

b

c

a

c

(1)next

-1

0

0

-1

1

(2)next

-1

0

0

0

1


下标

0

1

2

3

4

5

6

7

T

a

d

C

a

d

C

a

d

(1)next

-1

0

0

-1

0

0

-1

0

(2)next

-1

0

0

0

1

2

3

4

kmp实现如下:

int kmp(char *s, char *p){int m = strlen(p);int n = strlen(s);int *next = new int[m];GetNext(p,next);int i = 0, j = 0;while(i < n && j < m){if(j == -1 || s[i] == p[j]){++i;++j;}elsej = next[j];}delete []next;if(j == m)return i-m;else return -1;}




0 0
原创粉丝点击