问题的提出:
前几天,网友提出了一个问题:找出一段文本中连续出现次数最多的子串。
据说,这是微软的面试题。
据说,这是微软的面试题。
乍一看,这个问题有点无从下手。难不成要列出所有可能的子串一个一个搜索计数?
我们还是先寻找一些规律。
最基本的,长度为 n 的字符串 S 多次连续出现 S1 S2 S3……,
则每次出现的起始位置P(S1) P(S2) P(S3)……,两两之间的差是相等的:P(S1) - P(S2) = P(S2) - P(S3) ……。
好像有点废话,但这确实是个规律。
以此,我们就可以设计一个简单的算法。
我们还是先寻找一些规律。
最基本的,长度为 n 的字符串 S 多次连续出现 S1 S2 S3……,
则每次出现的起始位置P(S1) P(S2) P(S3)……,两两之间的差是相等的:P(S1) - P(S2) = P(S2) - P(S3) ……。
好像有点废话,但这确实是个规律。
以此,我们就可以设计一个简单的算法。
一个简单的算法:
举个简单的例子,比如输入的文本为“sabsababsabab"。
对于长度为 N 的文本 T ,我们可以按照子串的不同长度 n(1<= n <=K,K<=N/2)多次遍历文本查找在 n 步长的情况下相同的子串:
初始化 MAX_REPEAT = 1 // 只要字符出现就有一次了
STEP = 1 TO N / MAX_REPEAT
STEP = 1:
sabsababsabab
<- sabsababsabab
------------
没有相同的子串
STEP = 2:
sabsababsabab
<- sabsababsabab
----12---12
R1 R2
R1 是连续两个字符相同,它的重复次数是 REPEAT = COUNT(R1) / STEP + 1 = 2,即连续出现 2 次,由于 REPEAT > MAX_REPEAT,则令 MAX_REPEAT = REPEAT(并清除原有的结果),并保留结果 R1。
R2 的情况相同。
得到两个长度为 2 的子串R1 R2,他们均连续出现 2 次
STEP = 3:
sabsababsabab
<- sabsababsabab
123---12--
R3 R4
R3 是连续 3 个相同的字符,重复次数是 COUNT(R1) / STEP + 1 = 2。由于 REPEAT = MAX_REPEAT,保留该结果。
R4 是连续 2 个相同的字符,重复次数是 COUNT(R1) / STEP + 1 = 1。 由于 REPEAT < MAX_REPEAT, 该结果。
STEP = 4:
sabsababsabab
<- ...ababsabab
---------
没有相同的子串。
STEP = 5:
sabsababsabab
<- ...babsabab
-1234567
R5
找到长度为 7 的相同的子串 R5,重复次数为 REPEAT = COUNT(R1) / STEP + 1 = 2。 REPEAT = MAX_REPEAT,保留该结果。需要注意的是,连续相等的字符有 7 个,大于当前的步长 5,这意味着它有若干个长度为 5 的子串都是连续出现 2 次。
......
最终得到的结果是:
R1 : ab
R2 : ab
R3 : sab
R5 : absab
bsaba
sabab
对于长度为 N 的文本 T ,我们可以按照子串的不同长度 n(1<= n <=K,K<=N/2)多次遍历文本查找在 n 步长的情况下相同的子串:
初始化 MAX_REPEAT = 1 // 只要字符出现就有一次了
STEP = 1 TO N / MAX_REPEAT
STEP = 1:
sabsababsabab
<- sabsababsabab
------------
没有相同的子串
STEP = 2:
sabsababsabab
<- sabsababsabab
----12---12
R1 R2
R1 是连续两个字符相同,它的重复次数是 REPEAT = COUNT(R1) / STEP + 1 = 2,即连续出现 2 次,由于 REPEAT > MAX_REPEAT,则令 MAX_REPEAT = REPEAT(并清除原有的结果),并保留结果 R1。
R2 的情况相同。
得到两个长度为 2 的子串R1 R2,他们均连续出现 2 次
STEP = 3:
sabsababsabab
<- sabsababsabab
123---12--
R3 R4
R3 是连续 3 个相同的字符,重复次数是 COUNT(R1) / STEP + 1 = 2。由于 REPEAT = MAX_REPEAT,保留该结果。
R4 是连续 2 个相同的字符,重复次数是 COUNT(R1) / STEP + 1 = 1。 由于 REPEAT < MAX_REPEAT, 该结果。
STEP = 4:
sabsababsabab
<- ...ababsabab
---------
没有相同的子串。
STEP = 5:
sabsababsabab
<- ...babsabab
-1234567
R5
找到长度为 7 的相同的子串 R5,重复次数为 REPEAT = COUNT(R1) / STEP + 1 = 2。 REPEAT = MAX_REPEAT,保留该结果。需要注意的是,连续相等的字符有 7 个,大于当前的步长 5,这意味着它有若干个长度为 5 的子串都是连续出现 2 次。
......
最终得到的结果是:
R1 : ab
R2 : ab
R3 : sab
R5 : absab
bsaba
sabab
程序:










































































































































测试 1 :
Text :"sabsababsabab
"
Result :
--------
4 2:ab
9 2:ab
0 3:sab
1 7:absab
1 7:bsaba
1 7:sabab
--------
Total :4
Bye!
测试 2 :
Text :"sabsabsababsababsabababc
sabsabsababsababsabababc
sabsabsababsababsabababc
"
Result :
--------
17 4:ab
42 4:ab
67 4:ab
0 6:sab
25 6:sab
50 6:sab
4 12:absab
4 12:bsaba
4 12:sabab
29 12:absab
29 12:bsaba
29 12:sabab
54 12:absab
54 12:bsaba
54 12:sabab
0 50:sabsabsababsababsabababc
--------
Total :10
Bye!
小结:
不难看出,这个算法简单倒是简单了,但是它的时间复杂度,尽管用了各种办法减少循环次数,依然是O(N*N)数量级的。
那么还有什么办法能提高效率吗?
那么还有什么办法能提高效率吗?
未完,待序……
@@_
相关文章: 《出现次数最多的子字符串?——其实没那么复杂》, 《一次遍历找出“出现次数最多的子串”》