HDU-3746 Cyclic Nacklace

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3746


题目大意:

给你一个字符串,要求将字符串的全部字符最少循环2次需要添加的字符数。

例子:

abcabc 已经循环2次,添加数为0

abcac 没有循环2次,添加字符abcac。数目为5.

abcabcab 已经循环过2次,但第三次不完整,需要添加数为1


解题思路:

next[]数组的运用。

这里需要深刻理解next数组的含义,所以需要花费一定的功夫去弄懂这些。。

对于next数组,经过3天的学习,有了一定的认识。自己总结一下吧。

首先,求next数组有两种方法。第一种是严蔚敏教授那本数据结构上的求法。代码如下:

void getnext(const char *s) { int i = 0, j = -1; nextval[0] = -1; while(i != len) { if(j == -1 || s[i] == s[j]) nextval[++i] = ++j; else j = nextval[j]; } }
这种求法的含义是:

next[i]代表了前缀和后缀的最大匹配的值(需要彻底明白这点,相当重要)

另外一种是对这种算法的改进版本,代码如下:

void getnext(const char *p) //前缀函数(滑步函数) { int i = 0, j = -1; nextval[0] = -1; while(i != len) { if(j == -1 || p[i] == p[j]) //(全部不相等从新匹配 || 相等继续下次匹配) { ++i, ++j; if(p[i] != p[j]) //abcdabce nextval[i] = j; else //abcabca nextval[i] = nextval[j]; } else j = nextval[j]; //子串移动到第nextval[j]个字符和主串相应字符比较 } }
改进的地方在于-1的运用,关于怎么优化我已经写过了。自己看下就行了。。。但是一定要明白。

不同之处:

没有优化的getnext函数,next数组存的是前缀和后缀的最大匹配值,而优化后的getnext函数存的是在这个基础,进行更高效的改进。

比如abcabca

改进前最后一个字符next[7]=4,表示的是前缀和后缀最大匹配是4,即abca和abca。

改进后的next[7]=-1。这点也需要彻底搞懂,才能灵活的运用next函数。

总结一下:

在求前缀和后缀的最大匹配值时,要使用第一种,也就是未优化的算法。在运用KMP时,使用第二种算法,因为避免了多余的判断,更加高效。

YY:

其实我们可以发现KMP算法的精华部分是一个DP。每次右滑时,都是根据前面状态得到的有用信息进行的。相当于记忆化更新。这样算法才具有了很高的效率。

当然,理解这个算法确实需要仔细反复的研究,反正我是看了3天,才把这点基础东西搞的差不多,算是理解了80%吧。剩下的在以后做题的过程中慢慢发现吧。。。。


这道题的代码如下:

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define N 100010 char s[N]; int nextval[N]; int len; void getnext(const char *s) { int i = 0, j = -1; nextval[0] = -1; while(i != len) { if(j == -1 || s[i] == s[j]) nextval[++i] = ++j; else j = nextval[j]; } } int main() { int ncase; int length, add; scanf("%d", &ncase); while(ncase--) { scanf("%s", s); len = strlen(s); getnext(s); /*for(int i = 0; i <= len; ++i) //查看next数组的内容 cout<<nextval[i]<<" "; cout<<endl;*/ length = len - nextval[len]; //循环节的长度 if(len != length && len % length == 0) //循环多次 printf("0\n"); else { add = length - nextval[len] % length; //取余的作用:abcab,去掉abc printf("%d\n",add); } } return 0; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值