字符串匹配算法

一、暴力求解法(朴素算法)

实现代码:

int BF(char *str,char *sub,int pos)//暴力求解在一个字符串中查找字串出现的首次位置
{
 int lenstr = strlen(str);
 int lensub = strlen(sub);
 int i = pos;//主串
 int j = 0;
 while(i < lenstr && j < lensub)
 {
  if(str[i] == sub[j])
  {
   i++;
   j++;
  }
  else
  {
   i = i-j+1;//两个不匹配时,i退回上一次的下一个位置(此时i相对上一个位置已经走了j步)
   j = 0;    //j退回最开始
  }
 }
 if(j >= lensub)//此时代表找到
 {
  return i-j;//i-j代表字符串首次出现的位置
 }
 return -1;//没有找到
}

二、KMP算法
KMP 算法:相对于 BF 算法来说 KMP 算法更为高效,原因在于 BF 算法的时间复杂度是:O(mn) m 代表主串的长度,n 代表子串的长度。而 KMP 的话,时间复杂度就变为 O(m+n);接下来我们看一下,具体的实现 过程,还是一样,我们举例来看:KMP 和 BF 唯一不一样的地方在,我主串的 i 并不会回退,并且 j 也不会移动到 0 号位置。
(1)next数组:也就是用 next[j] = k;来表示,不同的 j 来对应一个 k值,
这个 k 就是你将来要移动的 j 要移动到的位置。
next[i]表示除去第i个数,字符串里从第一个数到第i-1个字符串
前缀和后缀最长重复的个数。

nextval数组:从第二位开始,若要求nextval[i],将next[i]的值与对应位的值进行比较(如:i的值为‘b’,next[i]=3,则将i的值与第3位的值进行比较),若相等nextval[i]=nextval[next[i]],若不相等,nextval[i]=next[i];
(2)k值的求解:
1>:找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标 0 开始,另一个以 j-1 下标结尾。
2>不管什么数据 next[0] = -1;next[1] = 0;在这里,我们以下标来开始,而说到的第几个第几个是从 1 开始; -1 的理由:当主串为–”defrdes” 子串为:”abc” 一开始就匹配失败。 0 的理由:当子串在 1 号下标匹配,此时为 0;

next数组的代码实现:

void GetNext(int*next,char *sub)//KMP的next数组
{
 next[0] = -1;
 next[1] = 0;
 int j = 2;
 int k = 0;
 int len = strlen(sub);//字串的长度
 while(j <= len)
 {
  if(k == -1 || sub[k] == sub[j-1])//Pk==Pj的情况
  {
   next[j] = k+1;
   j++;
   k = k+1;
  }
  else
  {
   k = next[k];//找不到最长的可以往前退,找长度较小的前缀后缀串
  }
 }
}

KMP算法的代码实现:

int KMP(char *str,char *sub,int pos)//KMP算法,从pos位置开始查找
{
 int i = pos;
 int j = 0;
 int lens = strlen(str);//主串的长度
 int lensub = strlen(sub);//子串的长度
 int  *next=(int *)malloc(lensub*sizeof(int));
 assert(next!=NULL);
 GetNext(next,sub);//调用GetNext函数得到next数组
 while(i<lens&&j<lensub)
 {
      if(j==-1||str[i]==sub[j])
      {
        i++;
        j++;
      }
      else
      {
       j=next[j];
      }
  }
  if(j>=lensub)
  {
    return i-j;
  }
  return -1;

三、统计子串在主串中出现的次数

int KmpCount(char *str,char *sub,int pos)//统计子串在主串中出现了多少次
{
 int lens = strlen(str);
 int lensub = strlen(sub);
 int i = pos;
 int j = 0;
 int count = 0;//记录出现的次数
 int *next = (int *)malloc(sizeof(int) *(lensub+1));
 GetNext(next,sub);
 while(i < lens)
 {
  //如果匹配到此时j处于next[j]的下一个位置,
  //回归到next[j]
  if(j>=lensub)//匹配到一个
  {
   count++;
   j = next[j];//j回到next[j]的位置
  }
  if(str[i] == sub[j]||(j==-1))
  {
   i++;
   j++;
  }
  else 
  {
   j = next[j];
  }
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值