poj2406

15103812_cSEt.gif 15103812_CBQv.gif View Code

    
/*Poj2406题解:
if (len % (len - next[len]) == 0 ),则重复子串的长度为 len - next[len].
证明如下,next[len]表示到len为止,满足既是前缀子串又是后缀子串的最长长度,
如下图{a,c}
= {b,d}
若len
% (len – next[len]) == 0 ,则说明{ a ,b} 的长度可以被{a, d} 的长度整除,同样可以被{b,c}的长度整除。
而此时,由于{b,c}是{b,d}的前缀子串又是后缀子串且保持{a,b}的长度可以被{a,c}整除。
这样,{a,c}就相当于原来的{a,d},而{b,c}就相当于原来的{b,d},通过这样的划分主串在不断减小,同样保持了len
% (len - next[len]) == 0的性质,不断划分的最后结果就是最后一次划分为2个相当的前后子串即重复子串。
Kmp的精髓:用kmp每次求得的next值就是当前到i为止的前子串与后子串相等的长度。*/

// kmp算法
#include " iostream "
using namespace std;
char s[ 10000001 ];
int next[ 10000001 ];
int L;
int i,j;
void Index_kmp()
{
while (i < L) // kmp核心算法
{
if (j == 0 || s[i] == s[j]) // 继续比较后继字符
{ ++ i; ++ j; next[i] = j; }
else
j
= next[j]; // 串向右移动
}
}
int main()
{
while ( 1 )
{
scanf(
" %s " ,s);
if (s[ 0 ] == ' . ' ) break ;
L
= strlen(s);
i
= 1 ; j = 0 ; next[ 0 ] = 0 ;

Index_kmp();
if (L % (L - next[L]) == 0 ) printf( " %d\n " ,L / (L - next[L])); // 形成周期性
else printf( " 1\n " );
}
return 0 ;
}

转载于:https://my.oschina.net/garyun/blog/602934

这道题目属于字符串分解的经典问题之一,目的是将一个较长的字符串拆解为尽可能多的完全相同的子串拼接而成的形式。下面是具体的思路解析、代码框架设计以及需要注意的地方。 --- ### **核心思想** 我们需要找到一种方法来确定最长的重复单位子串。具体做法可以分为以下几个步骤: 1. 构造一个新的辅助字符串:将原始字符串 `s` 拼接到自身之后形成新的字符串 `t=s+s`, 但是去掉首尾各一位元素得到最终版本`t'=t[1:-1]`. 2. 再利用KMP(Knuth-Morris-Pratt)算法寻找原字符串`s`在新构造出来的字符串`t'`里的最早出现位置index. 3. 根据所得的位置索引 index 计算得出最大可能分割数目k=len(s)//(len(s)-index). 4. 特殊情况考虑,若index等于零表示整个字符串是由单一字符构成,那么直接返回字符串总长度即可. --- ### **详细解释与示例** 举个例子说明一下这个过程: 假设我们的目标字符串S="abcabcabc" - 第一步生成T='bcabcabca' 然后应用KMP找寻模式串"S"出现在文本串"T'"中的首次位置Index: | i | T'[i]| prefix length| |--|------|---------------| |0 |b | | |...|.....|...............| 最后发现第一次完整匹配发生在第三个字符开始处(Index=3), 所以我们可以推导出 S 最少由 (Length of String)/(Position)=9/(9-3)=3段相同的部分组成。 --- ### **注意事项** 1. 要注意边界条件处理好,特别是当输入只有一个字母或者"."的时候应该怎样合理反馈。 2. 因为涉及大量字符串操作,所以选择合适的数据结构非常重要,在python语言里面推荐使用bytearray而不是普通的string因为前者支持就地修改效率更高;而在C++则可以用vector<char>. --- ### 示例代码(Python版): ``` python def maxRepeat(s): if len(set(s)) == 1 or s=='.': return len(s) t = (s + s)[1:-1] pi = [0]*len(t) for i in range(1,len(t)): j = pi[i-1] while(j>0 and t[j]!=t[i]): j=pi[j-1] if(t[j]==t[i]):j+=1 pi[i]=j pos = pi[-1] return int(len(s)/(len(s)-pos)) # Main Function to read multiple lines until '.' import sys lines=sys.stdin.readlines() for line in lines[:-1]: print(maxRepeat(line.strip())) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值