HDU-3363 Count the string KMP 巧用next函数

HDU-3363 Count the string KMP 巧用next函数

  正如题目所说,该题正是巧用next函数求得的,题目意思:给定一个串,求以它自身长度为(1,2,3…… N)的子串作为模式串,以完整的自身作为母串,求最后所得到的总匹配数。  其中样例中的 abab 结果是 6( a 出现两次, ab出现两次, abc出现一次, abcd出现一次 ), aaaa的输出结果应该为 10 ( a出现四次, aa出现三次, aaa出现两次, aaaa出现一次 )。

  还记得前面三道KMP题,一道(1711)是搜索返回是否成功匹配,一道(2087)是搜索模式串出现多少次(母串不可重复计算), 最后一道(1686)同样是搜索模式串出现多少次(当然母串可以重复计算),难度是依次递增。这次这道题目也算是在第三题的基础上演变而来,本来以为这一题与1686差不多,我找出所有第一个字母出现的下表,收集为一个索引表,然后再进行KMP匹配,每次只要匹配到一个字母那么以这个字母的前缀匹配数就加上一。数据是过了,但也只有在超时时才追悔莫及。

  其实在写KMP的时候就觉得很像getnext(  )函数,因为我正在做的事情就是将自己与本身串进行比较。最终的结果说明,这里只需运行一个getnext(  )函数就能够将此题解决,因为这很好了贴切了这个题目的意思,将自身与自身进行匹配。

  现就串 ababababa 进行拆解:

  1. 首先运行getnext(  )函数,我们将会得到这个串的 next[] 表,这里可以得到 next[] 表:

      A.  011234567   

     2. 再对next[]表的意义做进一步分析,首先我们应该明确所有的字符对应next[]值均是由上一个字符匹配的结果所得到的,这也解释了为什么我们要单独将next[1]赋为0,要知道这时候我们的匹配工作还没有开始。设k= next[i], k的值的意思是说,到 i- 1 号 字符,并且以 i- 1 号为终点,以某一点为起点,与本身从 1 号字符开始成功且最大可能的与本身匹配了k个字符(方向均为从左到右)。即满足  str[ 1, 2, 3…… k- 1 ]= str[ i- k+ 1, i- k+ 2, i- k+ 3…… i- 1 ],由于在求next的过程中,每次匹配成功我们并没有回溯模式串的指针,因此这样能够保证每个next[]的值均是最大的。回到问题上来,看如何利用next[]值来解决这道题目,第一个字符next[]值无意义,因为首字符的前面谈不上匹配成功。从第二个字符开始,A串的意思: (注意橙色字体) 可以转化为 001234567 这就是还原了之后的匹配值( 处理时就是在 自增之前进行处理 ),即每一位表示到当前位置时,最多匹配了多少字符。

  3. 最后分析如何计算前缀匹配总值,这里我们需要重新开辟一个数组来记录到达每一字符时会新出现多少个前缀匹配,用rec[]表示,初始化rec[1]= 1; 这表示到第一个字符时,就与自身匹配构成1种情况。 已知第5个字符的匹配值为3,那么到达这个字符时的那么新出现的匹配前缀应该为 rec[3]+ 1, 前面的rec[3]是因为这里出现了前三个字符的重复段,后面的 1 是因为 str[1-5] 本身的一个前缀串。 理清了这些关系,代码就可以写下来了。

  代码如下:

#include <iostream>
#include <cstring>

using namespace std;

char mix[200005];   /*_*/   int next[200005], rec[200005];

void getnext( char *s, int *n )
{
	int k= 1, j= 0, len= strlen( s+ 1 );
	next[1]= 0, rec[1]= 1;
	while( k<= len )
	{
		if( j== 0|| s[k]== s[j] )
		{
		    rec[k]=( rec[j] + 1 )% 10007;
			++k, ++j;
		    n[k]= j;
		}
		else
		{
			j= n[j];
		}
	}
}

int main(  )
{
	int T, N;
	cin>> T;
	while( T--&& cin>> N )
	{
		memset( rec, 0, sizeof( rec ) );
		cin>> mix+ 1;
		int len= strlen( mix+ 1 ), ans= 0;
		getnext( mix, next );
		for( int i= 1; i<= len; ++i )
		{
			ans+= rec[i]% 10007;
		} 
		ans %= 10007;
		cout<< ans<< endl;
	}
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/110584.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • fastai教程_euleros安装教程

    fastai教程_euleros安装教程从fast.ai学到的十大技巧:如何在几周内上手顶级算法https://www.colabug.com/3887239.htmlfastai系列教程(二)-快速入门MNIST示例https://www.pytorchtutorial.com/fastai-tutorial-2-overview-mnist/…

  • vs2019安装和使用教程(详细)

    vs2019安装和使用教程(详细)本篇博客是vs2017安装和使用教程(详细)的姊妹篇vs2019已经在4月2日正式发布,vs2019发布会请看这个链接:vs2019发布活动vs2019和vs2017一样强大,项目兼容,不用互相删除,而且C/C++,Python,F#,ios,Android,Web,Node.js,Azure,Unity,HTML,JavaScript等开发都可以执行,相关介绍可以看这个官方网址:Vi…

  • Navigator对象,获取浏览器类型userAgent,机器类型platform

    Navigator对象,获取浏览器类型userAgent,机器类型platformJavaScript常用事件集合,前端小白必备(写的很详细,建议收藏)1.文档加载事件鼠标事件获取浏览器类型,手机机型(容易出问题的地方)事件冒泡与事件委托(面试重点)一、获取浏览器类型letuserAgent=navigator.userAgent;console.log(userAgent);if(userAgent.indexOf(“Opera”)>-1){ //判断是否是Opera浏览器console.log(“Opera”);};

  • ods数据库是什么意思_数据仓库ods层和dw层的区别

    ods数据库是什么意思_数据仓库ods层和dw层的区别这两天看书,发现了和数据仓库相关的还有一个叫ODS的概念,它是企业级的全局数据库,用于提供集成的,企业级一致的数据,包含如何从各个子系统中向ODS抽取数据以及面向主题的角度存储数据。它和数据仓库的主要区别:数据仓库是面向主题的、集成的、随时间变化的、非易失的、用于进行战略型决策的数据集合。ODS是一个面向主题的、集成的、可变的、当前的细节数据集合,用于支持企业对于即时性的、操作性的、集成的全体信息…

  • php 7.1 openssl_decrypt() 代替 mcrypt_module_open() 方法

    php 7.1 openssl_decrypt() 代替 mcrypt_module_open() 方法

  • python基础01

    python基础01python简介诞生:创建人:GuidoVanRossum(荷兰人)时间:1989年python的应用领域系统运维网络编程(搜索引擎,爬虫,服务器编程)科学计算人工智能,机器人云计

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号