POJ 2406(KMP) 证明

来源:互联网 发布:ubuntu默认字体 编辑:程序博客网 时间:2024/05/16 14:27

KMP的精髓就是next数组是求pattern的某个后缀是其前缀。求法是递推。


len%(len-1-next[len-1]) == 0 则是幂等的串(应该是叫幂等吧?哈哈。自创)

数目就是len/(len-1-next[len-1])




这题我想的证明是分情况,

1.前缀后缀有重叠,那么画个图

abcdefg比如a-e==c-g就是说next[g] = c

那么a=c, b=d,c=e,d=f,e=g

如果len%(len-next[len-1])==0,那么就是说len能整除ab的长度,ab的长度也等于fg的长度。而两者之间的,后缀cg的前半部分c-f=a-d,cd是重合部分,长度相等,那么ab长度等于ef长度。

前缀af的后半部分重叠部分,cf=


2.前缀后缀没重叠,那么必然前后缀相邻,不然没法是幂等的。又因为前后缀相等,所以就幂等了。



KMP的实现,千万不要用网上的常见方法,很坑爹,是错的。

#if 0
void GetNext(char *s, int n)
{
    int i = 0;
    int j = -1;
    next[0] = -1;
    while (i < n) {
        if (j == -1 || s[i] == s[j]) {
            ++i;
            ++j;
            next[i] = j;
        } else
            j = next[j];
    }
}
#endif

这种东西你让人怎么理解。比如aaab这个串,求出来next竟然是 next[0] = -1 , next[1] = 0, next[2] = 1, next[3] = 2.

next[3]怎么能等于2呢。这是人家代码实现问题了。这种实现是错误的


算法导论上面的写法


void GetNext(char *s, int n)
{
    int i = 0;
    int j = -1;
    next[0] = -1;
    for (i = 1; i < n; i++) {
        while(j>=0 && (s[j+1]!=s[i]))
            j = next[j];
        if (s[j+1] == s[i])
            j++;
        next[i] = j;
    }
}

很好理解next求出来分别是-1,0,1,-1所以我那个公式len%(len-1-next[len-1]) == 0就是对的。

如果用网上的那种,应该是len%(len-next[len]),要用到next数组最后一个元素的后面一个位置才行。





#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>


using namespace std;


char s[1000001];
int next[1000001];


#if 0
void GetNext(char *s, int n)
{
        int i = 0;
        int j = -1;
        next[0] = -1;
        while (i < n) {
                if (j == -1 || s[i] == s[j]) {
                        ++i;
                        ++j;
                        next[i] = j;
                } else
                        j = next[j];
        }
}
#endif
void GetNext(char *s, int n)
{
        int i = 0;
        int j = -1;
        next[0] = -1;
        for (i = 1; i < n; i++) {
                while(j>=0 && (s[j+1]!=s[i]))
                        j = next[j];
                if (s[j+1] == s[i])
                        j++;
                next[i] = j;
        }
}


void Kmp(char *a, char *b, int an, int bm)
{
        int i = 0;
        int j = -1;
        for (i = 0; i < an; i++) {
                while (j >= 0 && b[j+1]!=a[i])
                        j = next[j];
                if (b[j+1] == a[i])
                        j++;
                if (j == bm - 1) {
                        printf("pattern occurs with shift %d\n", i+1-bm);
                        j = next[j];
                }
        }
}


int main()
{
        while(1) {
                //memset(s, 0, sizeof(0));  // scanf will add '\0'
                memset(next, 0, sizeof(0));
                scanf("%s", s);
                char pattern[1024];
                scanf("%s", pattern);
                if (strcmp(s, ".") == 0) break;
                int len = strlen(s);
                GetNext(s, len);
#if 1
                //if (len == 2 && s[0] != s[1]) // my new GetNext function according CLRS will cover this.
                //      printf("1\n");
                if (len%(len-next[len-1]-1) == 0) {
                        printf("%d\n", len/(len-next[len-1]-1));
                } else
                        printf("1\n");
#endif
#if 0
                if (len%(len-next[len]) == 0)
                        printf("%d\n", len/(len-next[len]));
                else
                        printf("1\n");
#endif
                Kmp(s, pattern, len, strlen(pattern));
        }


}

原创粉丝点击