初学KMP ->HDU1711

题意: 给你两个数组,求子数组在木数组出现的位置

Sample Input

2
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 1 3
13 5
1 2 1 2 3 1 2 3 1 3 2 1 2
1 2 3 2 1

Sample Output

6
-1
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
const int maxn = 1e6+20;
int nxt[maxn];
int n,m;
int s[maxn];//母串 
int t[maxn];//子串
void getnxt()   //求子串的next数组 最大前后缀 
{
	    i=1;
    int j=0;
	nxt[0]=0;
	while(i<m)
	{   //当然在未出现相等之前都nxt都赋予0 
		if(t[j]==t[i])   //j是第一位 ,i从第二位开始 ,如果相等了,说明出现了相同前后缀 
		{
			nxt[i]=++j;   //然后开始next数组  先记录i,然后i,j都++  
			i++;        //第i位若相等的话就应该是已经存在相同前后缀了,故先+1->++j; 
		}
		else if(!j)   //j=0,i++往后挪 
		{
			i++;
		}      //当有一次相等的话,该条件就不会存在了 
		else
		{                  // 123124   eg: 此时到a[5]  nxt[4]=2 检索a[5]时 i=5 j=2 nxt[j-1]=0,j=0; 
			j=nxt[j-1];   //若是不相等的话       j返回到前缀的最后一个相等的nxt指 即123124 返回的是a[1] 的nxt值 
		}
	}
}  
} 
int kmp()
{
	int i=0;
	int j=0;
	while(i<n&&j<m)          //对子母 进行检索 
	{
		if(s[i]==t[j])
		{
			i++;
			j++;
		}    //若都相等的话都向后挪 ++ 
		else if(!j)
		{
			i++;
		}
		else
		{
			j=nxt[j-1];
		}           //类同于求nxt 
	}
	if(j==m) return i-m+1;       //若到最后能够遍历到j  则在母串中的位置为i-m+1 
	else return -1;      //否则返回-1 
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d %d",&n,&m);
		for(int i=0;i<n;i++) scanf("%d",&s[i]);
		for(int i=0;i<m;i++) scanf("%d",&t[i]);
		getnxt();

	 
		printf("%d\n",kmp());
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/cgmm2333/article/details/81811398