KPM算法(附视频网站与代码)

KPM算法
最主要的内容就是求解:最长公共前后缀数组:
可以参考如下视频讲解:
https://www.youtube.com/watch?v=dgPabAsTFa8&t=623s
很清晰;
仅仅贴出看完视频之后所编写的代码,部分地方有微妙的改动。
其中有关于最长公共前后缀数组的优化:思想就是剔除不必要的移动操作,
比如match字串如果为aaaab,如果比较了第5位知道不相等,可以直接将子串移动到最先开始的位置,因为前4个字母是相等的.
优化部分的代码如下:

#include<iostream>
#include<string>
#include<vector>

//author:L
//done:2017:12/17
//KPM
using namespace std;
void prefix_table(string& pattern,int* prefix,int n);
int key_match(string& src,string& match,int* prefix,int mod);//mod = 0 raw, 1:kpm
int key_match_kpm_find_all(string& src,string& match,int* prefix,int* result);
int main(){
  string src;
  string match;
  int result[50] = {0};
  getline(cin,src);
  getline(cin,match);
  int len = match.size();
  int* prefix = new int [len];
  prefix_table(match,prefix,len);

  cout<<key_match(src,match,prefix,0)<<endl;
  cout<<key_match(src,match,prefix,1)<<endl;

  len=key_match_kpm_find_all(src,match,prefix,result);
  if(len==0){
     cout<<"does not exist the same string";
  }
  else{
    cout<<"find it ,the position are:"<<endl;
    for(int i=0;i<len;i++){
     cout<<result[i]<<" ";
    }
  }
  return 0;
}
void prefix_table(string& pattern,int* prefix,int n){
  int len = -1;
  int i = 0;
  prefix[0] = -1; //忘记了这一步
  while(i<n){
    if(len ==-1 ||pattern[len]==pattern[i]){
      ++len;
      ++i;
      prefix[i] = len;
    //可以做如下优化
    /*
     if(prefix[len] == prefix[i]){
       prefix[i] = prefix[len];
     }
     else{
       prefix[i] = len;
     }
    */
    }
    else{
      len = prefix[len];  //prefix回溯;
    }
  }
}
int key_match(string& src,string& match,int* prefix,int mod){
  int len_src = src.size();
  int len_match = match.size();
  int i = 0;
  int j = 0;
  if(len_src<len_match){
    return -1;
  }
  if(mod == 0){
    while(i<len_src && j<len_match){
      if(j==-1 || src[i] == match[j]){
        ++i;
        ++j;
      }
      else{
        j = prefix[j];
       }
    }
  }
  else{
     while(i<len_src && j<len_match){
       if(src[i] == match[j]){
         ++i;
         ++j;
       }
       else{
         i = (i-j)+1;晦朔+1;
         j = 0; //忘记的一步;
       }
     }
  }
  if(j == len_match){
    return i-j;
  }
  else{
    return -1;
  }
}
int key_match_kpm_find_all(string& src,string& match,int* prefix,int* result){
  int len_src = src.size();
  int len_match = match.size();
  int i = 0;
  int j = 0;
  int flag = 0;
  if(len_src<len_match){
    return 0;
  }
  while(i<len_src){
    if(j==-1 || src[i] == match[j]){
      ++i;
      ++j;
    }
    else{
      j = prefix[j];
    }
    if(j == len_match){
     result[flag] = i-j; //记录找到的位置
     flag++;
    }
   }
 return flag;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值