从KMP原理原理出发解决问题

网上已经很多对具体过程的解释 我就不再赘述 这里 我只说一下 我对KMP算法的理解

ps:刚开始 也是想了好久 但是始终不得其解 后来 看了算法导论 然后想了想 就明白了

KMP算法原理

前提:next数组构造成功
如果匹配到pos位置匹配失败 那么在模式串中的匹配位置回跳到patten[0…pos-1]这个串的公共前后缀的下一个位置 这样就节省了匹配前缀的时间 KMP优化思想就在这里

next数组

void get_next(int lastPos)
{
    int i=1,j=0;
    next[0] = 0;
    next[1] = 0;
    while(i<=lastPos)
    {
        if(patten[i]==patten[j])
        {
            if(j==0)
                next[i] = 0;
            i++;
            j++;
            next[i] = j;
        }
        else
        {
            if(j==0)
            {
                next[i] = 0;
                i++;
            }
            else
                j=next[j];
        }
    }
}

匹配算法

bool cast(int strLastPos,int pattenLen)
{
    int i=0;int j=0;
    while(i<=strLastPos)
    {
        if(patten[j]==str[i])
        {
            i++;j++;
        }
        else
        {
            if(j==0)
                i++;
            else
                j = next[j];
        }
        if(j==pattenLen)
        return true;
    }
    return false;
 } 

PS:如果看到这里 明白大致原理 但是还有那么一些模糊 推荐你去bilibili 去查 KMP算法 下面有一个汪看了也会懂的一个视频 讲解的非常透彻。
FINISHED!

更新时间2017.11.23

从书上发现了更精简的版本 然后自己写了一遍 orz

更新版

原先我们的next数组 到零了还得加一个if判断 更新版的next数组首元素是-1 所以就和匹配到相同的 做了合并,非常完美! 顺便带上匹配函数(首匹配+返回匹配串的第一个字符下标)

#include<cstdio>
const int maxn = 1e7;
int next[maxn];
char p[maxn];
char s[maxn];
#include<cstring>

void get_next(int ltp) 
{
    int i=1,j=0;
    next[0] = -1;
    while(i<=ltp)
    {
        if(j==-1||p[i]==p[j])
        {
            i++;
            j++;
            next[i] = j;
        }   
        else
        {
            j = next[j];
        }
    }
}
int cast(int ltp,int plen)
{
    get_next(strlen(p)-1);
    int i=0,j=0;
    while(i<=ltp)
    {
        if(j==-1||s[i]==p[j])
        {
            i++;j++;
        }
        else
        {
            j = next[j];
        }
        if(j==plen)
            return i-plen+1;
    }
    return -1;
}
int main()
{
    while(1)
    {
        scanf("%s%s",p,s);
        printf("%d\n",cast(strlen(s)-1,strlen(p)));
    }
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值