定义:线性存储的一组数据(默认是字符)

串的匹配

给定一段文本string,给定一个模式pattern,求pattern在string中的位置。
令string 长度为n,pattern长度为m

#include <string.h>
char string[]="aaabbbccc",pattern[],*p="bbb";
p = strstr(string,pattern); //T=O(nm)
if(p != NULL)
  printf("%s",p);//bbbccc

KMP

kmp需要pattern中有如下特点:首部的字串和尾部的字串相同。

设s指向string待比较的元素,p指向pattern待比较的元素。当前字符匹配时,s++,p++。
当匹配到如下图所示时,x与c不匹配。此时,s不移动(指向x),p向前移动到p=2(1+1)的位置,继续匹配。

算法-KMP
如何知道要移动到p=3?这就需要match数组来记录了。match数组记录了若当前字符不匹配时,p的取值。
算法-KMP
时间复杂度O(n+m)

对于任意j>0,match[j] 最大为match[j-1]+1。如果match[j] 有更大取值,则match[j-1]是不正确的。 如果第j个元素有子串可以匹配,则该字串中和第j个元素匹配的前一个元素必和第j-1个元素相等。那么只需要找和第j-1个元素匹配的字符,并判断该字符(设角标为k)的后一个字符是否与第j个元素匹配,若匹配,则match[j] =match[k]+1。

算法-KMP

void  init_match(char p, int match){
  int len = strlen(p);
  match[0] = -1;
  for(i=0;i<len;i++){
      j= match[i-1];
      while( j>=0 && pattern[j+1] != pattern[i]){
         j = match[j];
      }
      if( pattern[j+1] == pattern[i])
        match[i] = j+1;
        else 
        match[i] = -1;
  }  
}

int kmp(char str[],char p){
   int i=0,j=0,n,m;
   n = strlen(str);//O(n)
   m = strlen(p); // O(m)
   int match[m];
   init_match(p,match); //O(n);
   while(i<n &&j<m){ //O(n)
       if(str[i] == p[j]){
          i++;
          j++;
       }else if(j>0) {// 如果不是pattern的开头匹配不上
            j = match[j-1]+1;//当前字符不匹配,需要移动到前一个字符的match
        }else {// pattern的开头也匹配不上
           i++;
        }
   }
   return (j == m)?i-m:-1;
}

reference

浙大 数据结构 mooc https://www.icourse163.org/course/ZJU-93001?tid=1003013004

相关文章: