KMP--找子串

来源:互联网 发布:勒夏特列原理 知乎 编辑:程序博客网 时间:2024/06/08 04:20

问题概述:输入两个数n和m,再依次输入n个数作为串a,再输入m个数作为串b,请判断b串是否为a的子串,若是则输出b串在a串的起始点

输入样例:                                                                        对应输出:

2                                                                        6

13 5

1 2 1 2 3 1 2 3 1 3 2 1 2

1 2 3 1 3


KMP算法(专用于求解字符串匹配问题)步骤:

①定义一个数组next[m]用于对应子串(b[m]),next[i]=j表示b[1~j]和b[i-j+1, i]完全相等且b[i]!=b[j]

②初始化i=j=1(串中第一个)

③i++, j++,如果a[i]==b[i]执行步骤5,否则执行步骤4

④b串向后挪,由b[j]对应a[i]变为b[next[j]]对应a[i](j=next[j]),如果next[j]==-1则表示a[i]完全不能对应字串b中的任何一个元素,i++, j=0

⑤判定是否已经匹配完毕,如果没有继续执行步骤3

(在最后3个步骤中,如果i超过a的范围,表示匹配失败,结束)

原理:http://www.matrix67.com/blog/archives/115

复杂度:O(n+m)


#include<stdio.h>#include<string.h>int n, m;int a[1000005], b[10005], next[10005];void getnext();int kmp();int main(void){int T, i;scanf("%d", &T);while(T--){scanf("%d%d",&n,&m);for(i=0;i<=n-1;i++)scanf("%d", &a[i]);for(i=0;i<=m-1;i++)scanf("%d", &b[i]);if(n<m){printf("-1\n");continue;}getnext();printf("%d\n", kmp());}return 0;}void getnext(){int i, j;i = 0, j = -1;next[0] = -1;while(i<m){if(j==-1 || b[i]==b[j]){i++, j++;if(b[i]==b[j])/*虽然到这里可以满足b[1~j]和b[i-j+1,i]完全相等,但是因为b[i]=b[j],如果b[i]无法匹配,那么b[j]一定无法匹配*/next[i] = next[j];elsenext[i] = j;}else    /*如果b[i]和b[j]不相等,则说明后面不可能存在在i-j=k(k为定值)的情况下b[1~j]和b[i-j+1,i]完全相等,拉开i与j的距离*/j = next[j];}}int kmp(){int i, j;i = j = 0;while(i<n){if(a[i]==b[j])/*匹配成功,i++,j++,继续匹配*/{if(j==m-1)return i-j+1;i++, j++;}else{j = next[j];/*匹配不成功,b串向后挪,由b[j]对应a[i]变为b[next[j]]对应a[i],即j=next[j]*/if(j==-1)/*如果next[j]==-1表示a[i]完全不能对应字串b中的任何一个元素,i++,j=0*/i++, j = 0;}}return -1;}


原创粉丝点击