字符串匹配

在文本中查找对应的模式成为字符串匹配:

文本:T

模式:P

一:朴素的字符串匹配算法

思路:(1)首先有两个游标i,j指向文本和模式的位置

(2)当T[i]=P[j]时i++,j++,继续往下比较。

(3)当T[i]!=P[j]时,i回溯到上次开始比较的下一位,j回溯到0

(4)当找到一段连续的字符与模式字符串匹配最终模式字符串匹配成功,返回此次开始比较的文本位置。

int native_stringmatch(string *T,string *P)

{

int n=strlen(T);

int m=strlrn(P);

int s=0,i=0;

for(s=0;s<n-m;s++)//当文本串中剩余没有比较的元素的长度小于模式串时就不用在比了,是找不到的

{

   for(i=0;i<m;i++)

       {

      if(T[s+i]!=P[i])//当出现不匹配时此次比较结束

break;

if(i==m-1)//当P[i]==T[s+i]一直到了模式串的最后一个元素,则表明匹配成功

{

cout<<"匹配成功";

return s;

}

            }

}

return -1;

}

最坏时间复杂度为O((n-m+1)*m),性能较差


KMP算法

个人愚见:

文本串:s

模式串:P

s的长度为n,P的长度为m,且m<<n

引入概念失败数组:next[j]=k;

(1)最开始当然是s的首字符与p的首字符比较,如果不相等就下一个与p的首字符比较,设s的下标为i,P的下标为j。刚开始时i=j=0;

(2)当s[i]≠[j]时,匹配失败不要回溯i。以为在此之前可能有已经匹配好的元素,如果在此进行匹配会浪费时间。此时移动j,使得j=next[j];用s[i]与p[j]比较。

(3)情况:当j=-1时则用s[i+1]和p0比较

(4)当最终j==p的长度的时候,匹配成功,此时,在模式串中的位置为:i-j;

解释一下next[j],对于p中的每一个元素都求出其对应的next[j];对于p[j]其next值应为:p0p1p2p3p4pj-1中真前缀和真后缀中相同的最长长度。对于j=0时,其为-1,当没有相同的真前缀和真后缀时,next[j]=0;

 1 /**
 2      * KMP算法
 3      *
 4      * @param ss 主串
 5      * @param ps 模式串
 6      * @return 如果找到,返回在主串中第一个字符出现的下标,否则为-1
 7      */
 8     public static int KMP(String ss, String ps) {
 9         char[] s = ss.toCharArray();
10         char[] p = ps.toCharArray();
11 
12         int i = 0; // 主串的位置
13         int j = 0; // 模式串的位置
14         int[] next = getNext(ps);
15         while (i < s.length && j < p.length) {
16             //①如果j=-1,或者当前字符匹配成功(即S[i]==P[j]),都令i++,j++
17             if (j == -1 || s[i] == p[j]) { // 当j为-1时,要移动的是i,当然j也要归0
18                 i++;
19                 j++;
20             } else {
21                 //②如果j!=-1,且当前字符匹配失败(即S[i]!=P[j]),则令i不变,j=next[j],j右移j-next[j]
22                 j = next[j];
23             }
24         }
25         if (j == p.length) {
26             return i - j;
27         } else {
28             return -1;
29         }
30     }

next[j]的求法:递归)

最大长度表右移一位,然后初值为-1;

 public int[] getNext(String ps) {
 2         char[] p = ps.toCharArray();
 3         int[] next = new int[p.length];
 4         next[0] = -1;
 5         int j = 0;
 6         int k = -1;
 7         while (j < p.length - 1) {
 8             //p[k]表示前缀,p[j]表示后缀
 9             if (k == -1 || p[k] == p[j]) {
10                 next[++j] = ++k;//即当p[k] == p[j]时,next[j+1] == next[j] + 1=k+1
11             } else {
12                 k = next[k];
13             }
14         }
15         return next;
16     }

优化的next:因为当p[j]=p[next[j]]时下一步必然还失配,当这种情况时:零next[j]=next[next[j]];

//优化过后的next数组求法
 2     public static int[] getNext(String ps) {
 3         char[] p = ps.toCharArray();
 4         int[] next = new int[p.length];
 5         next[0] = -1;
 6         int j = 0;
 7         int k = -1;
 8         while (j < p.length - 1) {
 9             //p[k]表示前缀,p[j]表示后缀
10             if (k == -1 || p[j] == p[k]) {
11                 //较之前next数组求法,改动在下面4行
12                 if (p[++j] == p[++k]) {
13                     next[j]=next[k];// 当两个字符相等时要跳过
14                 } else {
15                     next[j]=k;//之前只有这一行
16                 }
17             } else {
18                 k = next[k];
19             }
20         }
21         return next;
22     }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值