POJ 2752 Seek the Name, Seek the Fame

[url]http://poj.org/problem?id=2752[/url]

[size=medium]题意:找出所给串的所有前缀长度,使得所给串中这个长度的前缀==这个长度的后缀

[color=blue]Sample Input
ababcababababcabab
aaaaa

Sample Output
2 4 9 18
1 2 3 4 5[/color]

看了HDU 1686 Oulipo[url]http://972169909-qq-com.iteye.com/blog/1070507[/url]
相信next值的意义就很清晰了

下面给出描述: (i>1)[下标从0开始]
next[i]的意义就是:前面长度为i的字串的【前缀和后缀的最大匹配长度】

那么这题怎么利用这个性质呢?

详细分析一下:【就用上面的第一个例子说明吧】
[table]
|求出next值:[非修正]
|下标: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
|串: [color=blue]a b a b c a b a b[/color] [color=red]a b a b c a b a b[/color]
|
|next值: -1 0 0 1 2 0 1 2 3 4 3 4 3 4 5 6 7 8 [color=red]9[/color]|
[/table]
len2 = 18 next[len2] = 9
说明对于前面长度为18的字符串,【长度为9的前缀】和【长度为9的后缀】是匹配的, 即上图的蓝色跟红色匹配
也就是整个串的[color=red][b]最大[/b][/color]前后缀匹配长度就是9了
所以接下来根本[b][color=red]不需要考虑长度大于9的情况[/color][/b]啦

好了!既然现在只需考虑长度小于9的前后缀匹配情况,那么
[b][问题就转化成[color=blue]蓝色串的前缀[/color]跟[color=red]红色串的后缀[/color]的匹配问题了!!! [/b]
又因为[color=blue]蓝串[/color]==[color=red]红串[/color]
所以问题又转化成
[b][color=blue]找蓝串自己的前缀跟自己的后缀的最大匹配了!!![/color][/b]
那么我们现在就要找next[9]的值了【next[9]的含义:蓝串的最大前后缀匹配】

回忆第一步:我们找的是next[len2]=9【len2=18】
怎么使得第二部目标变成9【求next[9]】呢?
其实next[len2]=9同时可以表示为:最大匹配前后缀的【[color=red]前缀长度[/color]】
那么next[9]的意义就是:
【主串】的最大匹配前后缀的【[color=red]前缀[/color]】的【[color=red]最大匹配前后缀[/color]】了!!
也就是上面[color=blue]蓝串[/color]的前后缀最大匹配长度了!!

那么算法描述就是:
第一步:求next[len2], 即next[18] = 9;
第二步:把9代进来,即求next[9] = 4;
第三步:把4代进来,即求next[4] = 2;
第四步:next[2] = 0; 也就是下标2之前的串已经没有前后缀可以匹配了
所以答案就是: 2 4 9 18 【PS: 从小到大输出,18是串长,显然符合题意】
局部实现代码:
[/size]

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define L2 400005

int next[L2], len2, ans[L2];
char p[L2];
bool hash[L2];

void get_next()
{
int k = -1, j = 0;
next[0] = -1;
while (j < len2)
{
if (k == -1 || p[j] == p[k])
{
j++, k++;
next[j] = k;
}
else k = next[k];
}
}

int main()
{
int k, i, j;
while (scanf ("%s", p) != EOF)
{
k = 0;
memset (hash, false, sizeof(hash));
len2 = strlen (p);
get_next();
j = next[len2];
while (j > 0)
ans[k++] = j, j = next[j];
for (i = k - 1; i >= 0; i--) //倒过来输出,就是从小到大了
printf ("%d ", ans[i]);
printf ("%d\n", len2);
}
return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值