题目一:
http://topic.youkuaiyun.com/u/20070930/11/fa87b186-148e-4cc3-a582-013562e64de0.html
求给定的某一个字符串中的最长不重复子串的长度。
例如字符串s为:“abcdefgegcsgcasse”,其最长的不重复子串为“abcdefg”,长度为7
Answer1:
使用后缀数组,时间复杂度O(nlogn)
题目二:
2.5亿个int类型的整数, 现要将其中的重复数字去除. 内存仅有600M, 该如何做?
Answer1:
http://offer.kuxun.cn/T_HrB.Cat_5.FileId_201.OffSet_1767
2.5*10^8 * 4 = 1000 * 10^ 6 > 600 * 10^6 不能采用传统的排序后去重的方式.
考虑bitset的方式, 建立一个2^32(整型的最大位数)的数组(bitset),每一个bit位0或1代表该位上代表的整数是否出现过. 这样以来, 一次遍历2.5亿个整数, 得到bitset, 在遍历一次bitset, 就可以得到不含重复数字的整数序列.
所需要的内存大小位2^32 / 2^3 = 2^29 = 512M.
Answer2:
2.5亿整数一共1g,整数如果使用位图,那么需要4g/8=512M。由于内存只有600M,所以
分两批处理这些整数,第一次处理正整数,第二次处理负整数。那么位数组需要256M。
题目三:链表排序:
将链表中各结点地址p1,p2...存放在数组中, 对数组按照(*p)进行O(nlgn)的排序,得到p1',p2'...,调整原链表中的相互位置, head->next=p1' p1'->next=p2'...
题目四:最长公共子串问题广义后缀树解法O(n)
http://hi.baidu.com/lkf0217/blog/item/0ae210ad25281e0e4b36d681.html
Answer1:
最长公共子串(Longest common substring, 简称LCS)问题指的是求出给定的一组
字符串的长度最大的共有的子字符串。
举例说明,以下三个字符串的LCS就是 cde:
abcde
cdef
ccde
高效的查找LCS算法可以用于比较多篇文章的最长相同片段,以及生物学上的基因比
较等实际应用。
前几天写了一个穷举法的简单实现,感觉在数据量稍大时效率极低,所以今天上网查
了一些资料,找到了解决LCS问题的最佳算法并编程实现,程序效率得到了极大的提
高。
采用的是广义后缀树(Generalized Suffix Tree,简称GST)算法,就是把给定的N个
源字符串的所有的后缀建成一颗树,这个树有以下一些特点:
1.树的每个节点是一个字符串,树根是空字符串“”
2.任意一个后缀子串都可以由一条从根开始的路径表达
(将这条路径上的节点字符串依次拼接起来就可以得到这个后缀)
3.特别应注意任意一个子串都可以看作某一个后缀的前缀。既然每一个后缀
都可以由一条从根开始的路径表达,那么我们可以从根节点开始一个字符
一个字符的跟踪这条路径从而得到任意一个子串。
4.为了满足查找公共子串的需求,每个节点还应该有从属于哪个源字符串的
信息
由以上的定义我们不难看出,在这棵GST树上,如果找到深度最大并且从属于所有源
字串的节点,那么,把从根到这个节点的路径上的所有节点字符串拼接起来就是
LCS。
还是举例说明,上面提到的三个字符串【abcde cdef ccde】的所有后缀子串列表如
下:
(注:.1表示是从第一个串abcde来的,同理.2,.3分别表示从cdef,ccde来的)
abcde.1
bcde.1
cde.1
de.1
e.1
cdef.2
def.2
ef.2
f.2
ccde.3
cde.3
de.3
e.3
建成的GST如下图所示
(注:.1表示从属于第一个串,.123表示既从属于第一又从属于第二,第三个源串)
--/_______【abcde.1】
|
|_____【bcde.1】 .....最深的并且带.123的节点
| :
|_____【c.123】____【de.123】_______【f.2】
| |
| |__【cde.3】
|
|_____【de.123】___【f.2】
|
|_____【e.123】____【f.2】
|
|_____【f.2】
上图中虚线所指的【de.123】节点所表示的子串cde正是LCS
以上是一些基本概念,但是实际应用时还要涉及到构建GST树以及查找LCS的具体算
法,参考了网上的一些资料,我用java语言实现了这些算法,基本上可以以O(n)的时间
复杂度进行建树及查找处理。
如果对构建SuffixTree算法等细节感兴趣,可以到google上查阅相关资料。
我的Java源程序如下:
Answer2:
可以采用后缀数组的做法,将两个字符串s1和s2链接成一个字符串s(如s1=”abcdebcde”,s2=”ebcdg”,那么s=”abcdebcde#ebcdg*”)然后求s的后缀数组。对后缀数组进行排序,比较相邻的两个字符串,求相邻两个后缀的最长公共子串(并且这两个后缀必须不属于同一个字符串的子串),最后求出最长的公共子串。