我正在经历Wikipedia implementation of Cycle detection using Tortoise-and-Hare algorithm。使用Ruby语言,这是我实现的:
def tortoise_and_hare(sequence) tortoise = 1 hare = 2 while sequence[tortoise] != sequence[hare] tortoise += 1 hare += 2 end # Find start index of first repetition idx = 0 tortoise = 0 while sequence[tortoise] != sequence[hare] tortoise += 1 hare += 1 idx += 1 end # Find length of cycle starting from index idx length = 1 hare = tortoise + 1 while sequence[tortoise] != sequence[hare] hare += 1 length += 1 end [idx, length] end sequence = [2, 0, 6, 3, 1, 6, 3, 1, 6, 3, 1] idx, length = tortoise_and_hare(sequence) p sequence[idx, length]
这样做正常并返回[6, 3, 1]
。现在,
[2, 0, 6, 3, 1, 6, 3, 1]
,它将返回
空集。[2, 0, 6, 3, 1, 6, 6, 3, 1, 6, 6, 3, 1, 6]
返回[6, 3, 1]
,
但应该是[6, 3, 1, 6]
。我可以看到问题排在第三位
循环。所以我想我的问题是:
我尝试修改第二个循环以解决第一个问题(修剪序列足够小以使算法失败)并且它有效:
# Find start index of first repetition idx = 0 tortoise = 0 while sequence[tortoise] != sequence[hare] tortoise += 1 hare += 1 hare = tortoise if hare > sequence.length - 1 idx += 1 end
虽然我提出了另一种优雅的基于Regex的解决方案,但我仍然想了解更多有关上述算法的信息。
好奇的正则表达式解决方案:/(?<cycle>(\d+\s)+(\d+))\s\k<cycle>/
编辑:我理解为什么它不可能检测到重复的字符。但在这种情况下是否还有其他可能有用的算法?
答案 0 :(得分:0)
答案是你的代码很好,但你的样本集太小了。该算法没有声称在尽可能短的数据量中找到一个循环。
您链接的页面上数据集的定义定义了生成无限数据集的过程。这些数据最终必须重复,因为您的域名不受限制,但您的范围是有限的。
根据范围,此算法将需要更多或更少的数据来确定周期。你已经不再提供它了。
至于解决方案,我会选择吗?我将通过插入第一个数字来创建范围中每个数字的映射以及我找到它的位置。一旦发现重复,你就找到了你的周期。从第一个实例的位置到第二个实例之前的位置。这给出了线性运行时和N * M内存使用。 N =列表的大小M =值的范围
这是你想要的perl(生锈的perl)正则表达式:
$data = "1 2 3 4 5 3 4 5";
if ($data =~ /(?<c>\d).*?(\k<c>)/) {
print substr($data, $-[1], $-[2]-$-[1])."\n";
} elsif {
print "NO\n";
}
最糟糕的运行时间是n ^ 2,我想它只适用于单位数字(容易修复),但它更直接。