我正在经历Wikipedia implementation of Cycle detection using Tortoise-and-Hare algorithm使用ruby语言,这就是我实现的:
def龟兔(顺序)
乌龟=1
兔子=2
当序列[乌龟]!=顺序[兔子]
乌龟+=1
兔子+=2
结束
#查找第一次重复的开始索引
idx=0
乌龟=0
当序列[乌龟]!=顺序[兔子]
乌龟+=1
兔子+=1
IDX+=1
结束
#从索引idx开始查找周期长度
长度=1
兔子=乌龟+1
当序列[乌龟]!=顺序[兔子]
兔子+=1
长度+=1
结束
[IDX,长度]
结束
顺序=[2,0,6,3,1,6,3,1,6,3,1]
IDX,长度=乌龟兔(顺序)
P序列[IDX,长度]
它工作正常并返回[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]
。我看问题出在第三位
循环。
所以我想我的问题是:
维基百科上公布的算法是标准的吗?
我的第二个案子不对吗我知道周期检测是指无限长的序列,我的考试不是,但它仍然有一个周期。
如果情况是正确的,我们可以做些什么来改进算法并解决我上面指出的两个问题?
我试着修改第一个问题的第二个循环(修剪足够小的序列,使算法失败),它成功了:
#查找第一次重复的开始索引
IDX=0
乌龟=0
当序列[乌龟]!=顺序[兔子]
乌龟+=1
兔子+=1
兔子=乌龟如果兔子>序列。长度-1
IDX+=1
结束
它看起来是错的还是在某些情况下可能会失败?
对于第二个问题(重复字符),我们能做些什么?
虽然我准备了另一个优雅的基于正则表达式的解决方案,但我仍然想了解更多关于上述算法的信息。
好奇的正则表达式解决方案:/(?<cycle>(\d+\s)+(\d+))\s\k<cycle>/
编辑:我理解为什么它不可能检测到重复的字符但是在这种情况下还有其他的算法可以帮助吗?
最佳答案
答案是你的代码很好,但是你的样本集太小了该算法并不要求在尽可能短的数据量中找到一个循环。
链接页面上数据集的定义定义了生成无限数据集的过程这些数据最终必须重复,因为您的域是无限的,但您的范围是有限的。
根据范围的不同,该算法将需要更多或更少的数据来确定周期。你只是没有提供足够的。
至于我的解决方案呢?我会创建一个范围内的每个数字的地图,以及我从插入第一个数字开始找到它的位置一旦你找到一个重复,你就找到了你的周期。从一审的位置到二审之前的位置。这提供了线性运行时和n*m内存使用量。N=列表大小M=值范围
这是您想要的perl(rusty 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,我想它只适用于单个数字(很容易修复),但它更严格。