请查看原文:
http://www.ibaiyang.org/2012/03/25/repeat-substring/
最近在看《编程珠玑》,很多人说,应该看看这本神书,于是跟风,我也买了一本,不过才拿到这本书的时候,觉得也是一般,前面几章的例题很是一般,而且感觉作者分析的东西自己不是很实用,比如二分搜索就讲了2,3章,虽然作者对二份搜索的理解与实现,吹毛求疵,但是整体上来说,觉得没有意思,没有给人一张豁然开朗的感觉,在看到第二章时,讲到了变位词的算法,才令人痴迷,于是我疯狂的继续看下去,今天看到了重复字符串的实现方式,我高兴的立刻想发篇博文,来证实它多么的奇妙。
求一个字符串的最长重复字符串,就是在一个长字符串中,找出有重复的字符串,且其长度最长,我感觉这个题的引申意义也很大,特别在如今搜索引擎的时代。例如banana的最长字符串是ana,tian xian的最长字符串是ian。好了,看看是怎么实现的吧。
int cmp_str(char* p, char* q)
{
int size = 0;
while(p && q && *p == *q){
size++;
p++;
q++;
}
return size;
}
int maxlen = -1;
int current_size = -1;
for(int i = 0; i < n; i++){
for(int j = i + 1; j < n; j++){
if( (current_size = cmp_str(&input_string[i], &input_string[j]) ) > maxlen ){
maxlen = current_size;
low_index = i;
high_index = j;
}
}
}
其中最大的字符串长度存在原字符串中的i到j的位置,当然这是任何人都能想到的2B算法,我也包括在列,哎,继续努力吧。
那么,作者怎么看待这个问题的呢,其中用到了“后缀数组”,很早之前,就听某位ACM队员将过后缀数组,但是不知道他说的是什么,也没有追问,今天碰巧又遇到了它,冤家路窄啊。
什么是后缀数组呢,其实很简单,我觉得这个属于程序预处理部分,一个简单的数据结构。
这个结构是一个字符指针数组,假设记为word。读取字符时,我们对word进行初始化,使得每个元素指向输入字符串中的相应字符
int i = 0;
char ch;
while( (ch = cin.get()) != '\n' ){
input_string[i] = ch;
word[i++] = &input_string[i];
max_word++;
}
input_string[i] = '\0';
word[i] = NULL;
那么举个例子吧,如我们输入的字符串是baiyang,则
word[0] = "baiyang";
word[1] = "aiyang";
word[2] = "iyang";
word[3] = "yang";
word[4] = "ang";
word[5] = "ng";
word[6] = "g";
这些就成为“后缀数组”,如果你能理解二叉树,我相信这个也能理解吧。
如果某个长字符串在数组中出现二次,那么它将出现在二个不同的后缀中,因此我们队数组排序以寻找相同的后缀。
如对banana的后缀数组排序为
word[0] = "a";
word[1] = "ana";
word[2] = "anana";
word[3] = "banana";
word[4] = "na";
word[5] = "nana";
于是看到ana为最长,分别存在1,2二个后缀数组中。
当我们对后缀数组排好序之后,我们就可以遍历数组了
int i = 0;
int index = -1;
int max_len = -1;
int current_size = 0;
for(i = 0; i < max_word - 1; i++) { if( (current_size = cmp_str(word[i], word[i+1])) > max_len ) {
max_len = current_size;
index = i;
}
}
这样,最长的子字符串的长度就是max_len了,而起点就是index位置。故解决,算法复杂度由之前的n平方,降到了nlog(n)了。不过我觉得其中的后缀数组结构值得我们思考一下。
转载:http://www.ibaiyang.org/2012/03/25/repeat-substring/ 支持正版
-----------------打造高质量的文章 更多关注 把酒泯恩仇---------------
为了打造高质量的文章,请 推荐 一下吧。。。。谢谢了,请关注我后续的文章,会更精彩哦
请关注sina微博:http://weibo.com/baiyang26
把酒泯恩仇官方博客:http://www.ibaiyang.org 【推荐用google reader订阅】
把酒泯恩仇官方豆瓣:http://www.douban.com/people/baiyang26/
如果您想转载本博客,请注明出处
如果您对本文有意见或者建议,欢迎留言
分享到:
相关推荐
《JavaScript设计与开发新思维》一书由Larry Ullman撰写,是现代JavaScript开发者不可或缺的指南。本书聚焦于JavaScript在现代网页开发中的应用与设计思维,深入探讨了如何利用JavaScript来构建高效、可维护的代码,...
在C语言中,由于没有内置的字符串处理函数,因此我们不得不通过手动遍历字符串,逐字符判断并构建新的输出字符串。在实现这个功能时,我们需要注意以下几点:遍历整个输入字符串的过程中要跳过空格;非空格字符要...
Redis与传统的关系型数据库不同,它不仅能存储字符串类型的数据,还能存储其他复杂的数据结构,包括字符串列表、无序不重复的字符串集合、有序不重复的字符串集合、以及键值都是字符串的哈希表。Redis支持不同类型值...
- 乘法(`*`): 用于数字相乘,还可以用于列表、元组和字符串与整数的乘法,表示序列元素的重复。 - 真除法(`/`): 结果总是浮点数。 - 求整除(`//`): 结果是整数,向下取整。 - 取模(`%`): 返回除法的余数。 - **...
第三套题目是关于函数fun的功能,要求将一个数字字符串转换为一个整数(不得调用C语言提供的将字符串转换为整数的函数)。例如,若输入字符串"-1234",则函数把它转换为整数值-1234。 通过这100套题目,我们可以学习...
其中,起始符和结束符通常为固定字符,地址用于标识目标设备,命令字和参数则根据不同的功能需求而变化,校验位用于确保数据传输的完整性。 #### 第三章:命令字描述 IT8500系列电子负载支持多种命令字,按功能...
使用字符串操作来构建结果,确保没有前导零。 5. **优化处理**:为了节省空间和提高效率,可以只记录新出现的余数,而不是保存所有历史余数。同时,对于非循环部分,可以直接使用浮点数转换。 6. **边界条件**:...
- 遍历字符串,对于每一个起始位置,逐个字符向后移动,形成新的子串并加入哈希集合。 - 最终集合的大小即为不同子串的数量。 ##### 试题C: 数列求值 - **题目背景**:给定一个数列,从第四项开始,每一项都是前...
- **数据库(Database):**MongoDB 使用 UTF-8 字符串作为数据库名称,名称中不得包含特殊字符,并且长度不得超过 64 字节。 - **集合(Collection):**集合是 MongoDB 中的基本容器对象,用于存储文档。集合名称...
7.2.3 字符串过滤程序 256 7.2.4 整数溢出 256 7.2.5 类型转换错误 260 7.3 案例研究:IIS索引服务漏洞 262 7.3.1 CVariableSet:: 7.3.1 AddExtensionControlBlock 263 7.3.2 DecodeURLEscapes 267 7.4 结论 271 第8...