06-数据结构与算法(串的模式匹配学习笔记整理)

假设主串s和字符串t,字串t的定位就是要在主串s中找到一个与子串t相等的子串。

  1. Brute-Force算法

Brute-Force算法实现模式匹配的思想是:从主串s="s0s1…sn-1"的第一个字符开始和模式串t="t0t1…tn-1" 的第一个字符比较,若相等,则继续比较后续字符;否则从主串s的第二个字符开始重新与模式串t的第一个字符比较。如此不断继续,若存在模式串中的每个字符 依次和主串中的一个连续字符序列相等,则匹配成功,返回模式串t的第一个字符在主串中的下标;否则匹配失败,返回-1。

 

C#代码实现:

static int index(string s ,string t)

{

int i = 0, j = 0, k;

 

while (i<s.Length&&j<t.Length)

{

if (s[i]==t[j])

{//如果相等继续匹配

i++;

j++;

}

else

{//不相等时回溯

i = i - j + 1;

j = 0;

}

}

if (j>=t.Length)

{//匹配成功

k = i - t.Length;

}

else

{

k=-1;

}

return k;

}

2. KMP算法

KMP 算法的思想是:设s为主串,t为模式串,设i为主串s当前比较字符的下标,j为模式串t当前比较字符的下标,另i和j的初值为0. 当si= tj时,i和j分别增1再继续比较;否则i不变,j改变为等于next[j],再继续比较。依次类推,直到下列两种情况之一:一种是j退回到某个j = next[j] 时有si = tj;则i和j分别增1再继续比较;另一种是j退回到j = -1,此时令主串和模式串的下标各增1(此时模式串下标便退回0:j = j + 1 = -1 + 1 = 0),再继续比较。

其中,我们把模式串中从第一个字符开始到任一个字符为止的模式串中的真子串定义为next[j]函数,则next[j]函数定义为:

①next[j]= max{ k | 0<k<j 且"t0t1…tk-1" = "tj-ktj-k+1…tj-1"}     当此集合非空时

②next[j]= 0                                         其他情况

③next[j]= -1                                        当 j = 0 时

若模式串t中存在真子串"t0t1…tk-1" = "tj-ktj-k+1…tj-1",且满足0<k<j,则next[j]表示当模式串t中的tj与主串s的si比较不相等时,模式串t中需重新和主串s的si比较的字符下标为k,即下一次开始比较si和tk;若模式串t中不存在如上所说的真子串,有next[j] = 0,则下一次开始比较si和t0;当j = 0时,令next[j] = -1,此处-1为一标记,表示下一次开始比较si+1和t0.

简而言之,KMP算法对Brute-Force算法的改进就是利用已经得到的部分匹配结果将模式串t右滑一段距离再继续比较,从而无需回退主串s的下标值。

规则:

K:字符前的K个字符和字串的头K个字符相等

1.k=-1 只有模式串的第一个字符的k值为-1

2.K>0 表示指定字符前面k个字符和模式串的头k个字符相等

3.K=0 其他情况。(模式串第2个字符的k值必为0.)

 

KMP算法的缺点:

KMP算法的改进

K值的重新定义:

  1. t[i]=t[0],并且t[j]前面不存在n个字符跟模式串的头n个字符相等
  2. t[j]=t[0],t[j]前面存在n个字符跟模式串的头n个字符相等,但t[j]=t[n].

 

 

c#代码实现:

//求得K值

public static void GetNext(string t,int[] next)

{

int k = -1, j = 0;

 

next[0] = -1;

while (j<t.Length-1)

{

if (k==-1 || t[j]==t[k])

{

j++;

k++;

next[j] = k;

}

else

{

k = next[k];

}

}

}

static int KMPIndex(string s, string t)

{

int[] patt=new int[t.Length];

int i = 0, j = 0, v;

 

 

next.GetNext(t, patt);

while (i<s.Length&&j<t.Length)//正在匹配

{

if (j==-1 || s[i]==t[j])

{

i++;

j++;

}

else

{

j = patt[j];

}

}

if (j>=t.Length)//匹配成功

{

v = i - t.Length;

 

}

else

{

v = -1;

}

return v;

}

KMP算法改进:

public static string LCS(string str1,string str2)

{

if (str1==str2)

{

return str1;

}

 

 

int[] matrix = new int[str1.Length];//数据记录匹配数据

int maxlen = 0;//最大公共字串长度

 

int begin = 0;

 

if (string.IsNullOrEmpty(str1)||string.IsNullOrEmpty(str2))

{

return null;

}

 

for (int i = 0; i < str2.Length; i++)

{

for (int j = str1.Length - 1; j >= 0; j--)

{

if (str1[j]==str2[i])//字符相等

{

//比较的是第一列或第一行

if ((i==0)||(j==0))

{

matrix[j] = 1;

}

else

{//否则的话在左边基础上加一

 

matrix[j] = matrix[j - 1] + 1;

}

}

else//字符不相等

{

matrix[j] = 0;

}

if (matrix[j]>maxlen )

{//刷新最大公共字串

maxlen = matrix[j];

begin = j;//记录最大公共字串的位置

}

}

}

 

if (maxlen==0)

{

return null;

}

 

return str1.Substring(begin-maxlen+1,maxlen);

}

posted @ 2013-10-17 15:18  常想一二,不思八九  阅读(299)  评论(0)    收藏  举报