• kmp 字符串匹配


    kmp的详解在百度上有许多博客群雄辩舌,各有千秋。看着那些证明和解释实在吓人,太长了,今天回顾kmp发现自己已经忘的差不多了,去看百度也不愿意看,就给自己做个笔记,方便以后好回忆,再也不用被那些长篇大论吓到了。

    回忆第一步:算法用途

    在字符串1中找是否存在字符串2,eg:abxabwabxad中是否有abxad。

    回忆第二步:为什么要用算法

    暴力不行吗?呃呃呃,Time Limited。

    回忆第三步:节省时间的想法是什么

    每次暴力都产生了很多有用信息,比如第一次匹配到字符串2的最后一位发现不同后,我们不必从字符串1的b开始找,可以从第二个a开始找。 

    回忆第四步:怎么实现想法

    有一个next数组。

    回忆第五步:这数组干嘛用的

    next[i]表示字符串1中起点为0,终点为i的子串的最大前缀与后缀相同位数。

    回忆第六步:巴拉巴拉的缀是啥东东

    字符串eg:ababc,前缀是:a,ab,aba,abab  后缀是:c,bc,abc,babc

    ababa的最大前缀与后缀相同位数是3,aba

    回忆第七步:这数组怎么求,呃,要不暴力

    不用暴力,用一个标记k,遍历一遍字符串就可以了。

    回忆第八步:遍历一遍是怎么做到的,死狗欸

    好吧,回忆不起来了,那去看别人博客吧。

    过了一会儿。。。。

    好长啊,还是自己推吧。

    k可以初始化为0也可以初始化为-1。我用0吧。k是用来计数,既然用来计数我喜欢从0开始计算。

    原理很简单,就是两个指针同时移动,指针i会一直往后走,任性,而k是有变化的。k的计数可以来帮k确定位子。

    比较时有两种情况,第一种呢是如果两个指针指的字母相同,这说明前缀和后缀相同的位数可以加一位了,嘿嘿,k++。

    另一种情况呢,就是悲剧了,不相同,前缀和后缀不相同了,那k我要去哪呀,可谓何去何从?又回到最初的起点?不对不对,回到最初点是最糟糕的情况,你应该回到你刚刚上一步匹配到的巴拉巴拉缀那里去,即next[k-1],因为说不定回到这里又能和当前i匹配到了呢,不是吗,于是,你就乖乖用了一个while实现了这一步。走到最后你就把next数组求完了,时间复杂度为i的范围O(n),效率杠杠的。

    回忆结束,打坐休息。。。。

    敲得嘛得,不用实战训练一下吗?代码都还没给出来呢?不用实战我学这算法干嘛?我学这算法有何用?

    呃呃呃,就拿一题简单的求next数组的题来过过。

    题目链接:http://poj.org/problem?id=2406

    题目大意:定义字符串的乘法为a*b=a*b,a^4=aaaa,给出一个长度不超过一百万的字符串,求这字符串为某子串的最大幂。

    解题思路:所谓高手过招,只需一眼,因为我不是高手,我用了两眼

    第一眼:求next数组,得出某子串的长度为n-next[n-1],n是输入字符串的长度

    第二眼:求幂;如果n是子串长度的整数倍,说明可以幂,输出幂,否则该子串不能幂得到原串,即子串就是原串,输出1。

    最后献上ac代码(内含next数组求法标码):

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 using namespace std;
     5 const int maxn=10000007;
     6 int next[maxn];
     7 char str[maxn];
     8 void initnext(int len)
     9 {
    10     int k=0;
    11     for(int i=1;i<len;i++)
    12     {
    13         while(k>0&&str[k]!=str[i]) k=next[k-1];
    14         if(str[k]==str[i]) k++;
    15         next[i]=k;
    16     }
    17     return;
    18 }
    19 int main()
    20 {
    21     while(~scanf("%s",str))
    22     {
    23         if(str[0]=='.')
    24             break;
    25         memset(next,0,sizeof(next));
    26         int len=strlen(str);
    27         initnext(len);
    28         if(len%(len-next[len-1])==0)
    29             printf("%d
    ",len/(len-next[len-1]));
    30         else
    31             printf("1
    ");
    32     }
    33     return 0;
    34 }
  • 相关阅读:
    Google Map API使用详解(三)——Google Map基本常识(上)
    Google Map API使用详解(十)——使用JavaScript创建地图详解(上)
    sethc.exe
    taobao_java
    "void __cdecl operator delete[](void *)" (??_V@YAXPAX@Z) 已经在 LIBCMTD.lib(delete2.obj) 中定义 错误
    some Content
    变参 C++ 转帖
    阅读大型程序你得到什么
    一些模块
    a common jsp
  • 原文地址:https://www.cnblogs.com/wwq-19990526/p/10802455.html
Copyright © 2020-2023  润新知