hiho_KMP算法

经典的KMP算法,但是本人由于这周一直在乱忙,美来的及提交上,其实还是理解了好久这道提目题目详见hiho第三周。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Solution{
public:
  int kmp(const string &patternStr,const string &sourceStr){
    int patternSize=patternStr.size();
    vector <int> next(patternSize+1,0);
    calculateNext(patternStr,next);
 
    /***************
    cout<<"   ";
    for(int i=0;i<patternSize;i++){
      cout<<patternStr[i]<<" ";
    }
    cout<<endl;
    for(int i=0;i<=patternSize;i++){
      cout<<next[i]<<" ";
    }
    cout<<endl;
    ****************/
    
    int sourceSize=sourceStr.size();
    int q=-1;//pattern串的已匹配位置
    int result=0;
    for(int i=0;i<sourceSize;i++){
      while(sourceStr[i]!=patternStr[q+1]){
        if(q==-1){
          break;
        } 
        q=next[q];
      }
      //当前位置匹配成功模式串对齐点+1
      if(sourceStr[i]==patternStr[q+1]){
        q++; 
      }
      //完成一次匹配
      if(q==patternSize-1){
        result++;
        //从当前匹配成功的源串起始位置继续下一次匹配
        i=i-q+1;
        q=-1;
      }      
    }
    return result;
  }
  void calculateNext(const string &pattern,vector <int> &next){
    next[0]=-1;
    next[1]=-1;
    int q=-1;//q表示模式串当前的匹配位置
    //i表示当前源串匹配位置
    //pattern[q+1]和pattern[i-1]分别代表前缀和后缀需要对齐的位置
    for(int i=2;i<=pattern.size();i++){ 
        while(pattern[i-1]!=pattern[q+1]){ 
          if(q==-1){
            break;
          }
          q=next[q];
        }
        if(pattern[i-1]==pattern[q+1]){
          q++;
        }
        next[i]=q;
    }
  }
};

int main(){
  Solution ss;
  //ss.kmp("bacbacbbcabac","");
  int n=0;
  cin>>n;
  string patternStr;
  string sourceStr;
  for(int i=0;i<n;i++){
    cin>>patternStr;
    cin>>sourceStr;
    cout<<ss.kmp(patternStr,sourceStr)<<endl; 
  }
  return 0;
}


前面的算法整体上来看是O(n2),但是在网上查KMP算法的时间复杂度应该是O(n),看了别人的码才知道自己还是没有真正理解KMP算法的精髓,记得在Baidu知道上一个大牛说KMP的本质是保证在匹配过程中源串不存在回溯操作,

再加上之前自己的理解:根据模式串的纯前缀和纯后缀的最长公共子串的中间结果进行匹配,代码如下,这是别人的代码,最近越来越觉得学会看别人的代码才是真正的成长:

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

int main()
{
    char t[10050],s[1000007];
    int c;scanf("%d",&c);
    while(c--)
    {
        scanf("%s%s",t,s);
        int flink[10004]={};
        int i=0,j=-1;
        flink[0]=-1;
        int len=strlen(t);
        while(i<len)
        {
            if(j==-1 || t[i]==t[j])
                flink[++i]=++j;
            else
                j=flink[j];
        }
        int ans=0;
        i=j=0;
        int n=len;
        len=strlen(s);
        while(i<len)
        {
            if(j==-1 || s[i]==t[j])
            {
                ++i;++j;
            }
            else
            {
                j=flink[j];
            }
            if(j==n) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值