zoukankan      html  css  js  c++  java
  • kmp算法,poj1226示例

    kmp算法的主要作用:

    给出两个字符串str1,str2

    str1: a c a c b a c b a b c a

    str2: a c b a b

    利用kmp算法能够求出str2在str1中首次出现时的位置。

    kmp算法的原理:

    普通暴力方法求出子串首次出现的位置算法复杂度为O(nm),而利用kmp可以将复杂度降到O(n+m)

    kmp到底什么地方神奇呢?它最神奇的地方在于它能够利用已经匹配成功的成果

    第一趟匹配

    str1: a c a c b a c b a b c a

    str2: a c b a b

    第二趟匹配

    str1: a c a c b a c b a b c a

    str2:      a c b a b

    第三趟匹配

    str1: a c a c b a c b a b c a

    str2:              a c b a b

    关键在于第二趟匹配失败后将str2向后移动了多少

    这时候kmp算法的作用就出来了,很容易发现str2向后移动多少跟串str1是没有关系的

    所以str2自身就可以确定比较某个字符失败后向右移动多少位置

    我们用一个数组next[]来记录str2的每一个字符匹配失败后需要向右的位移(也就是从某个下标重新比较)

    索引j     1 2 3 4 5

    str2      a c b a b

    next[j]  0 1 1 1 2

    这个next是如何确定的呢?

    用通俗一点的话来解释:

    当j == 1时 如果a与某个字符串的字符不相等,则j = next[j] 也就是j = 0;

    当j == 2时 如果c与某个字符串的字符不相等,则j = next[j] 也就是j = 1;

    当j == 3...                                                                  ......j = 1;

    当j == 4...                                                                  ......j = 1;

    当j == 5...                                                                  ......j = 2;

    我们发现当比较到str2[j]的时候 str2[j]前面n个元素如果跟str2[0]后的n个元素相同,那么next[j]+=n;

    这个如何解释呢,让我们来看一个例子:

    如果str2为abcabcdeaf

    当比较到红色的d的时候它的前三个字符abc与str2起始的三个字符abc相同

    那么当它与某个字符串的某个字符匹配失败的时候说明str2到d为止前面的字符全都比较成功了

    那么我们下次比较就可以不用比较相同的abc了直接从下一个也就是第四个元素a来对应原字符串就可以了

    举个例子:

    当比较

    str1 abcabc a bcdef

    str2 abcabc d ef

    时e和d不相同,可是前面的部分abcabc都相同,那么我们就可以往下这样进行

    str1 abcabc e bcdef

    str2      abc a bcdef

    这样我相信大家都能够理解了吧。

    那么用编程的方式怎么来实现求出某个字符串的next[]数组呢?

    我用c语言做一个例子:

    接下来我们只需要将str1和str2进行比较,如果有字符不相同就向后移动str2就可以了

    具体的算法描述为:

    接下来我们用kmp算法解决poj上1226题

    题目大意:找出n个串中最大的公共子串长度

    #include <stdio.h>

    #include <string.h>

    #define Maxn 101

    char str[Maxn][Maxn];

    int next[Maxn],rnext[Maxn];

    int T,n;

    void get_next(int s,int e,int flag)

    {

        int i,j;

        if(flag == 1)

        {

            next[s] = s - 1;

            i=s,j=s-1;

            while (i <= e) {

                if (j == s-1 || str[0][i] == str[0][j]) {

                    i++;j++;next[i]=j;

                }

                else

                {

                    j = next[j];

                }

            }

        }

        else

        {

            rnext[e]= e+1;

            i=e,j=e+1;

            while (i >= s) {

                if (j == e+1 || str[0][i] == str[0][j]) {

                    i--;j--;rnext[i]=j;

                }

                else

                {

                    j = rnext[j];

                }

            }

        }

    }

    int kmp(int k,int s,int e,int flag)

    {

        int i,j,len;

        len = strlen(str[k]);

        if(flag == 1)

        {

            for(i = 0, j = s; i < len && j <= e;)

            {

                if(j == s - 1 || str[k][i] == str[0][j])

                    i++, j++;

                else

                    j = next[j];

            }

            if(j > e)

                return 1;

        }

        else

        {

            for(i = 0, j = e; i < len && j >= s;)

            {

                if(j == e + 1 || str[k][i] == str[0][j])

                    i++, j--;

                else

                    j = rnext[j];

            }

            if(j < s)

                return 1;

        }

        return 0;

        

    }

    int main()

    {

        scanf("%d",&T);

        

        while (T--!=0) {

            scanf("%d",&n);

            

            for (int i = 0; i < n; i++) {

                scanf("%s",str[i]);

            }

            int len = (int)strlen(str[0]);

            int ans = 0;

            for (int i = 0; i < len; i++) {

                int l;

                for (int j = i; j < len; j++) {

                    get_next(i, j, 1);

                    get_next(i, j, 0);

                    l = j - i + 1;

                    int cnt=1;

                    for (int k = 1; k < n; k++) {

                        if (kmp(k, i, j, 1) ==1|| kmp(k, i, j, 0)==1) {

                            cnt++;

                        }

                        else

                            break;

                    }

                    if (cnt == n&& ans < l) {

                        ans = l;

                    }

                    

                    

                }

                

            }

            printf("%d ",ans);

        }

        return 0;

    }

  • 相关阅读:
    (ZOJ 3329) One Person Game (概率DP)
    python爬虫之json数据处理
    1034 Head of a Gang 图的遍历,map使用
    1030 Travel Plan Dijkstra+dfs
    vs C++ scanf 不安全
    1021. Deepest Root DFS 求最长无环路径
    1013. Battle Over Cities 用dfs计算联通分量
    无法解析的外部符号
    PAT DFS,BFS,Dijkstra 题号
    1004 Counting Leaves 对于树的存储方式的回顾
  • 原文地址:https://www.cnblogs.com/q403154749/p/3803303.html
Copyright © 2011-2022 走看看