zoukankan      html  css  js  c++  java
  • 【初识】KMP算法入门

    举个例子

    模式串S:a s d a s d a s d f a s d

    匹配串T:a s d a s d f

    如果使用朴素匹配算法——

    1 2 3 4 5 6 7 8 9 

    a s d a s d a s d f a s d

    a s d a s d f

    1 2 3 4 5 6 7

    此时,匹配到了S7和T7了,S7为a而T7为f,不匹配那么朴素的匹配算法会这么做——

    2 3 4 5 6 7 8 9 

    s d a s d a s d f a s d

      a s d a s d f

      2 3 4 5 6 7

    这时,我们会发现,模式串回溯到了S2,而匹配串回溯到了T1。

    很明显,这会极大的降低算法的效率,在最坏情况下,我们需要将模式串几乎每个元素都查询一次,而每次查询都从匹配串的串首走到接近串尾,这样的时间复杂度为n*m,其中n和m分别为模式串和匹配串的长度。

    那么我们是否有可能降低时间复杂度呢?答案是肯定的——很明显我们只需要想办法减少回溯,就可以达到效果。Kmp算法就是使用这种方法节省时间的。

    1 2 3 4 5 6 7 8 9 

    a s d a s d a s d f a s d

    a s d a s d f

    1 2 3 4 5 6 7

    这个东西很熟悉吧?刚刚出现过一次。

    那么,kmp算法会怎么执行下一步呢?答案如下——

    1 2 3 4 5 6 7 8 9 

    a s d a s d a s d f a s d

            a s d a s d f

            1 2 3 4 5 6 7

    注意这一步!这里的模式串根本没有回溯,只是将匹配串向后移动了若干步。这样,最坏情况只是将模式串走一遍,然后将匹配串走一遍,当然了,匹配串里面的部分元素会走多次,但是,很明显这种算法会将n*m降低到n+k,这个k和m内部部分元素的重复次数有关,最大不会超过n(当然这是我自己证明得到的,不一定正确,以后我还会继续证明的)。

    好了,方法知道了,那么怎么实现呢?

    换句话说,怎么实现迅速的移动匹配串呢?答案是——添加一个Next数组,标记匹配串中的特性。

    这个Next数组的特性很明显

    1. Next[0] = -1,即这是第一个元素,前面没有可以替换它的。
    2. Next[j] = k ; { k | T[0] = T[j-k], T[1] = T[j-k+1],... , T[k-1] = T[j-1]}。
    3. Next[j] = 0; 其他情况。

    举例:

    匹配串T: a  s  d  a  s  d  f

    Next:   -1  0  0  0  1  2  3

    具体见代码——

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 const int N = 2010;
     9 
    10 char s[N], t[N];
    11 int Next[N];
    12 int lenS, lenT;
    13 
    14 void kmpNext(char* T)                                           //计算Next数组
    15 {
    16     int i = 1;
    17     Next[0] = -1;                                               //Next[0] = -1
    18     while(i < lenT)
    19     {
    20         int j = 0;
    21         while(T[j] == T[i])                                     //Next[i] = j; { j | T[0] = T[i-j], T[1] = T[i-j+1],... , T[j-1] = T[i-1]}
    22         {
    23             Next[i] = j;
    24             i++;
    25             j++;
    26         }
    27         Next[i] = j;                                            //同上,或等于0
    28         i++;
    29     }
    30 }
    31 
    32 bool kmp(char* S, char* T)                                      //kmp
    33 {
    34     lenS = strlen(S);
    35     lenT = strlen(T);
    36     kmpNext(T);
    37     int i = 0, j = 0;
    38     while(i < lenS && j < lenT)                                 //当模式串或匹配串走完时退出
    39     {
    40         if(j == -1)
    41         {
    42             i++;
    43             j = 0;
    44         }
    45         else if(S[i] == T[j])
    46         {
    47             i++;
    48             j++;
    49         }
    50         else j = Next[j];
    51     }
    52     if(j == lenT) return 1;                                     //如果匹配串走完,表示匹配串是模式串的子串
    53     return 0;
    54 }
    55 
    56 int main()
    57 {
    58     //freopen("test.in", "r", stdin);
    59     while(~scanf("%s%s", s, t))
    60     {
    61         if(kmp(s, t)) printf("Yes
    ");
    62         else printf("No
    ");
    63     }
    64     return 0;
    65 }
    View Code
  • 相关阅读:
    linux下shell显示-bash-4.1#不显示路径解决方法
    update chnroute
    An error "Host key verification failed" when you connect to other computer by OSX SSH
    使用dig查询dns解析
    DNS被污染后
    TunnelBroker for EdgeRouter 后记
    mdadm详细使用手册
    关于尼康黄的原因
    Panda3d code in github
    Python实例浅谈之三Python与C/C++相互调用
  • 原文地址:https://www.cnblogs.com/mypride/p/4950245.html
Copyright © 2011-2022 走看看