扩展KMP Sunday算法

刷题刷到kmp了  TLE了 想着还是sunday算法高效一点 还好写

kmp和扩展kmp的思想都是在不匹配时如何高效移动原串的匹配起点
sunday直接判断步长为模式串的长度,效率最高
原串 s:fffsffkfsfff size n=12 匹配起点为i
模式串 p:fsf size m=3
每次匹配 s从i开始 p从0开始

if 匹配成功则记录,i转到下一位置
判断第i+m位,找该位字母在p中最后出现的位置k
if 存在 i移到 i+m-k 位
else i移到 i+m+1 位
e.g.  i=0
      fffsffkfsfff        
      fsf

       ^   

该位不匹配, i跳到 i+m = 3, s[3]=s, 在p中位置为k=1,i跳到i+m-k =2(其实就是转到长度一样的起点去判断

      fffsffkfsfff        
        fsf

           ^   

好了匹配成功

判断模式串每个字母最后出现位置用数组nex[ ]记录,遍历一遍p,更新就好,

nex初始化为-1, 这样 就一起解决原串中字母在模式串中找不到时i往后移一位的问题了  (i+m -k     i+m-(-1)  模式串中存在则位置更新,否则记为-1

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<list>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
typedef pair<char,char> Pc;
typedef long double ld;
#define mem(x) memset(x, 0, sizeof(x))
#define me(x) memset(x, -1, sizeof(x))
#define fo(i,n) for(ll i=0; i<n; i++)
#define sc(x) scanf("%lf", &x)
#define pr(x) printf("%lld\n", x)
#define pri(x) printf("%lld ", x)
#define lowbit(x) x&-x
const ll MOD = 1e9+7;
const ll oo = 0x3f3f3f3f;
const ll N = 2e6 +5;
char a[N];
ll nex[100];

void getnext(string s)
{
    me(nex);
    ll i, n=s.size();
    for(i=0; i<n; i++)
        nex[s[i]-'a']=i;
}
void Sunday(string s, string p)
{
    ll n=s.size(), m=p.size();
    getnext(p);
    for(ll i=0; i<m; i++) cout<<nex[p[i]-'a']<<" ";cout<<endl;
    ll i=0, j, k, t;
    while(i<=n-m)
    {
        j=i;
        k=0;
        while(j<n && k<m && s[j]==p[k])
            j++, k++;
        if(k==m) cout<<"match in pos"<<i<<endl;
        if(i+m<n)
            i+=(m-nex[s[i+m]-'a']);
        else {cout<<"not match"<<endl;return ;}
    }
}
int main()
{
    ll i, j, k, l=0;
    ll n, m, t;
    string s, p;
    while(cin>>s>>p)
    {
        Sunday(s,p);
        cout<<endl;
    }
    return 0;
}
View Code

 

posted @ 2019-05-20 19:55  op-z  阅读(187)  评论(0编辑  收藏  举报