我正在寻找一种算法来查找给定字符串的显性循环子字符串。
循环子字符串:
显性循环子字符串:
示例1:
prefixgarbagecyclecyclecyclecyclesufixgarbage
cycle
:=> cycle
是重复最多的相邻子字符串示例2:
prefixgarbagecyclepadinggarbagecyclesufixgarbage
g
:=> cycle
的出现不会相邻重复,g
相邻重复两次示例3:
prefixgarbagecyclecyclepadinggarbageprefixgarbage
cycle
:=> cycle
& g
相邻重复两次,但cycle
比g
示例4:
prefixgarbagecyclecyclecycleroundroundroundprefixgarbage
cycle
:=> cycle
& round
重复三次&相同的长度,但cycle
首先出现例5:
abcdefghijklmnopqrstuvqxyz
<empty string>
,因为没有重复的相邻子字符串实施此算法的最佳方法是什么?
答案 0 :(得分:2)
找不到比这个二次时算法更好的东西(用Python实现):
IREP, IPER, IPOS = 0, 1, 2
def find_dominant(src):
best = (0, 0, 0) # repetitions-1, period, position
period = 0
while period < len(src) // max(2, 1 + best[IREP]):
period += 1
length = 0
for pos in range(len(src) - 1 - period, -1, -1):
if src[pos] == src[pos + period]:
length += 1
repetitions = length // period
if repetitions >= best[IREP]:
best = (repetitions, period, pos)
else:
length = 0
return best
s = "prefixgarbagecyclecyclecyclecyclesufixgarbage"
res = find_dominant(s)
if res[0] == 0:
print("nothing found")
else:
print(res[IREP] + 1, '*', s[res[IPOS]: res[IPOS] + res[IPER]])
对于每个可能的周期,扫描字符串并记住最长的周期性子序列。向后扫描以检查较少的条件。当没有找到进一步的改善时,停止增加期限。
时间复杂度为O(N 2 / R),其中R是主要子串的重复次数。空间复杂度为O(1)。
答案 1 :(得分:1)
这是一种可行的方法(由于您的周期必须相邻,因此更简单)。选一个字符串。看看它是否重复。跟踪最重复的一个。
编辑实际测试的Python代码:
testStrings =[ "prefixgarbagecyclecyclecyclecyclesufixgarbage",
"prefixgarbagecyclepadinggarbagecyclesufixgarbage",
"prefixgarbagecyclecyclepadinggarbageprefixgarbage",
"prefixgarbagecyclecyclecycleroundroundroundprefixgarbage",
"abcdefghijklmnopqrstuvqxyz"];
for input in testStrings:
repCountMax = 0
longestCycle = ""
repCount = 0
for i in range (1, len(input)):
for j in range( i+1, len(input)):
substring = input[i:j]
#print substring
ls = len(substring)
repCount = 1
k = j
while(substring == input[k:k+ls]):
k = k + ls
repCount = repCount +1
#print "repetition ", repCount, " of ", substring, "\n"
if (repCount > repCountMax) or ((repCount == repCountMax) and len(substring) > len(bestCycle)):
repCountMax = repCount
bestCycle = substring
if repCountMax > 1:
print "best cycle in '", input, "' is '", bestCycle,"' which is repeated ", repCountMax, " times."
else:
print "no repeated cycles found in string ", input
结果输出:
'prefixgarbagecyclecyclecyclecyclesufixgarbage'中的最佳循环是' ecycl'重复4次。最好的周期' prefixgarbagecyclepadinggarbagecyclesufixgarbage'是'g',它是 重复2次。
最好的周期' prefixgarbagecyclecyclepadinggarbageprefixgarbage'是'ecycl' 重复2次。
最好的周期' prefixgarbagecyclecyclecycleroundroundroundprefixgarbage'是'ecycl' 重复3次。
在字符串中找不到重复的循环 abcdefghijklmnopqrstuvqxyz
注意 - 找到的周期为ecycl
,而不是cycle
。 ecycl
首先发生了......
第二个注意事项 - 当你不能再“击败”当前的最佳估计值时,你可以通过停止来提高效率 - 例如,如果你已经找到了5次重复,并且给出了你要搜索的字符串的大小没有六次重复的空间。当存在大量重复时,这将提高速度。请参阅Evgeny的解决方案,了解实现该方法的方法。
答案 2 :(得分:1)
从左向右扫描。
您需要一些键/值对。关键是一封信。该值包括扫描中找到该字母的最后一个字母实例的索引以及该字母属于两个或多个字符串所属的任何循环的信息(最后一个以该列中该字母开头)。
您需要一个地方来存储有关找到的任何周期的信息。称之为“自行车商店”。
扫描时,请在每个索引处执行此操作:
完成扫描后,查看循环存储以查看哪一个占优势。
请注意,您可能不必将所有周期存储到结束,但对我来说并不是很明显,如何确定哪些周期可以丢弃。可能是基于键/值对表的内容以及到目前为止的主导值保持仍然可能继续的那些。
答案 3 :(得分:0)
我认为可以在这里应用KMP算法的修改形式。
从头开始遍历字符串。
拿第一个字母,存放它。拿下一个字母,如果它相同,则有2个候选者重复循环,否则将其添加到现有字符串。
基本上,在每封信中,您都会有一份可能的重复列表子列表。当然,你必须记录长度和最大值。至此为止的重复。
如果我没有弄错的话,这可以在O(n)时间内完成。