POJ 2752 Seek the Name, Seek the Fame(next数组的应用)

本文探讨如何通过计算字符串的next数组来找到其所有前缀中与后缀相匹配的最长长度。通过实例分析,解释了如何利用next数组解决字符串匹配问题,并提供了算法实现的代码片段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

Sample Input 
ababcababababcabab 
aaaaa 

Sample Output 
2 4 9 18 
1 2 3 4 5
 

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

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

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

详细分析一下:【就用上面的第一个例子说明吧】 
求出next值:[非修正]
下标:      0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17
 
串:          a  b  a  b  c  a  b  a  b  a  b   a   b   c   a   b   a   b
 
next值:  -1  0  0  1  2  0  1  2  3  4  3   4   3   4   5   6   7   8   9

len2 = 18    next[len2] = 9 
说明对于前面长度为18的字符串,【长度为9的前缀】和【长度为9的后缀】是匹配的, 即上图的蓝色跟红色匹配 
也就是整个串的 最大 前后缀匹配长度就是9了 
所以接下来根本 不需要考虑长度大于9的情况 啦 

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

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

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

局部实现代码: 

#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;  
}  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值