POJ2406 & POJ1961 详细解题思路和AC程序 KMP算法变种

原创 2015年07月09日 00:48:00

poj2406

题目大意:

给出一个字符串s,求其最短的子串a,使得s=a^n(即n个a相连),输出n。s的长度小于10^6。


Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3




本题可以用kmp算法来做。

先算出next数组。有些KMP算法的代码中next[i]代表的是s[i+1]匹配不上时下一个位置,有些代码代表的是s[i]匹配不上时,本人用后者,即next数组要求到'\0'那位。


len表示s的长度(不包括'\0'),那么如果确实有长度非len的解的话,该子串的最小长度一定为(len-next[len])。

以上不证明了(因为不会证),参考kmp算法的原理脑补一下:p

但长度为(len-next[len])的子串不一定真的是解。比如:abcab,len-next[len]=3,长度为3的串abc或者cab显然不是解

所以需要判断len%(len-next[len])==0是否成立。


够了吗? 那么是否有必要扫描一遍s,判断是否s中存在的确实是len/(len-next[len])个该子串呢?

够了。


如下图,表示len==12,next[len]==8时的情景,len-next[len]==4,可以发现s即为3个长度为4的子串构成的



参考程序:

#include <stdio.h>
#include <stdlib.h>
char s[1000010];
int next[1000010];

int kmp_next(char s[])
{
	int k=-1,j=0;
	next[j]=k;

	while (s[j])
	{
		if (k==-1 || s[k]==s[j])
		{
			k++;
			j++;
			if (s[k]==s[j])
				next[j]=next[k];
			else
				next[j]=k;
		}
		else k=next[k];
	}
	return j;
}

int main()
{
	int len,i,ans,flag,j;
	scanf("%s",s);
	while (s[0]!='.')
	{
		len=kmp_next(s);

		ans=(len-next[len]);
		if (len%ans!=0)
			ans=len;

		printf("%d\n",len/ans);
		scanf("%s",s);
	}
	return 0;
}


POJ1961


题目大意:

给出一个字符串的长度和字符串s,对于其所有的前缀,设其长度为i,求最大的k(k>=2),使a^k=substring(s,0,i),若存在这样的k,输出i,k

输出所有满足的i,k对


Sample Input

3
aaa
12
aabaabaabaab
0

Sample Output

Test case #1
2 2
3 3

Test case #2
2 2
6 2
9 3
12 4




跟上题差不多,不过这回需要对next数组进行遍历。

同时注意求next数组的时候

			if (s[k]==s[j])
				next[j]=next[k];
			else
				next[j]=k;
如果有该优化的话,该优化得去掉,改成:

  next[j]=k;

原因见kmp算法原理




参考程序:



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

char s[1000010];
int next[1000010];

void kmp_next(char s[])
{
	int k=-1,j=0;
	next[j]=k;

	while (s[j])
	{
		if (k==-1 || s[k]==s[j])
		{
			k++;
			j++;
			next[j]=k;
		}
		else k=next[k];
	}
}

int main()
{
	int tt,len,i,l,j=0;
	scanf("%d",&len);
	gets(s);
	while (len!=0)
	{
		gets(s);
		kmp_next(s);

		printf("Test case #%d\n",++j);
		for (i=2;i<=len;i++)
		{
			l=i-next[i];
			if (i%l==0 && i/l>1)
				printf("%d %d\n",i,i/l);
		}

		printf("\n");
		scanf("%d",&len);
		gets(s);
	}
	return 0;
}



需要做更基础的kmp题的可以去做poj3461,poj2752




版权声明:本文为博主原创文章,未经博主允许不得转载。

高效面试之字符串匹配(KMP,AC算法)

文本Tn  模式Pm, P在T中出现的位置为偏移 字符串匹配问题描述为:找出所有偏移s(0= 分两步完成,预处理+匹配 算法 预处理时间 匹配...
  • cqkxboy168
  • cqkxboy168
  • 2014年10月26日 01:44
  • 1060

Trie、KMP、AC自动机小结

最近做了不字符串的题,做下小结吧~          首先是Trie(也叫前缀树),Trie的结构并不难理解,Trie是个树形结构,它的每条边对应一个字符,每个节点对应一个字符串的前缀(根节点对应空串...
  • qian99
  • qian99
  • 2014年02月05日 21:58
  • 1412

简单讲解KMP单模式匹配与AC算法多模式匹配(KMP篇)

前言 本篇是对于KMP单模式匹配以及AC算法多模式匹配的简单讲解,KMP算法与AC算法是关键字检索中的常见算法,能够快速而高效地查找出目标字符串中的多个关键字的匹配情况,而要检索的关键字通常被称为模...
  • class_brick
  • class_brick
  • 2017年01月12日 23:11
  • 571

AC-BM算法原理与代码实现(模式匹配)

AC-BM算法将待匹配的字符串集合转换为一个类似于Aho-Corasick算法的树状有限状态自动机,但构建时不是基于字符串的后缀而是前缀。匹配时,采取自后向前的方法,并借用BM算法的坏字符跳转(Bad...
  • fishmai
  • fishmai
  • 2016年08月31日 21:16
  • 920

KMP算法实现原理

KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法。...
  • caoyan_12727
  • caoyan_12727
  • 2016年09月16日 16:27
  • 2148

算法系列--Two Sum

继续算法系列。今天再看一道leetcode(www.leetcode.com)的题目。问题描述原文 Given an array of integers, find two numbers suc...
  • ylyg050518
  • ylyg050518
  • 2015年09月13日 23:34
  • 834

kmp算法 和例题 poj1961

题目   http://poj.org/problem?id=1961 刚开始做这个不知道什么是kmp算法    自己看了很多书籍介绍  没看懂   最后还是看课本知道了一点点 首先我来介绍kmp...
  • aibianchendewo
  • aibianchendewo
  • 2013年03月31日 22:27
  • 482

给初学编程解题没思路的学生的建议

一个通过评论完成的答疑——学生:老师,最近一直用您的C++程序设计课程学习和练习,老师给的答案详细明了,很容易懂,但是有些在自己写的时候很难想到,尤其是像类似于本文程序中对“输入的时间d天后是哪年哪月...
  • sxhelijian
  • sxhelijian
  • 2013年10月12日 16:14
  • 5200

KMP算法next数组计算方法的优化

KMP算法的原理就是利用相匹配的前缀子串与后缀子串,来确定失配时下次对齐的位置; 其中最关键的就是next数组的确立; 数据结构课本上经典的例子: void getNext(const char *...
  • sowhat_Ah
  • sowhat_Ah
  • 2014年12月26日 11:34
  • 17951

KMP 算法的实现过程讲解,图解加算法说明

KMP 算法的简单理解
  • man_sion
  • man_sion
  • 2017年03月29日 15:59
  • 454
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ2406 & POJ1961 详细解题思路和AC程序 KMP算法变种
举报原因:
原因补充:

(最多只允许输入30个字)