使用O(n)中的循环列表的约瑟夫斯概率

时间:2013-07-02 18:12:26

标签: algorithm data-structures josephus

我最近偶然发现了一个论坛,声称Josephus问题可以通过数据结构在O(n)中解决。这里明确的选择是循环链表,但我声称它只能在O(kn)或O(n ^ 2)中完成,除非你做维基百科的数学递归/迭代josephus算法。首先,循环链表具有以下属性:搜索O(n),删除O(1),追加O(1)。假设delete是给定节点,append正在替换head或tail。

如果我们有一个循环的节点列表,我们可以从起点找到要删除的节点,如下所示:

n = 6个节点

k =删除每个第3个节点

StartingPoint:节点#0

节点:0,1,2,3,4,5

我们可以通过(k + StartingPoint - 1)%n计算要删除的节点。对于startpoint = 0,我们有(3 + 0 - 1)%6 = 2.现在,3将是我们的起点。 (3 + 3 - 1)%5 = 0,当移位时是我们原来的5节点(即数字现在是0,1,2,3,4,因为原始2消失了)。这基本上是数学版本的工作原理。对于链表,我们可以导出哪个节点需要删除类似。问题是我们必须前往这个节点。链接列表有O(n)搜索,这是一个问题。所以我们遍历这个节点,删除它,现在我们有n = n-1。我们找到下一个索引,进行O(n)搜索并且n = n_original - 2.这变为n +(n-1)+(n-2)+ ... = O(n ^ 2)。

如果我们有一个双重链接的循环列表,那么如果节点距离我们较近,我们就不必全力以赴。如果k小于n,这是O(k)搜索,如果k大于n,则搜索O(n)(因为在你开始的地方之前你只能移动n个节点,但如果k很小,你只需要移开k,你就不会到达你开始的地方)。

无论如何,我的观点是我不知道如何通过O(n)中的数据结构来做到这一点。维基百科上的解决方案在O(n)中是一种非常优雅的数学方式,它显示了递归的强大功能(纯粹通过调用堆栈跟踪旧起点等),但是当删除实际对象时,似乎不可能获得O( N)。我想展示我尝试解决这个问题的尝试而不仅仅是公然要求,所以有人知道在O(n)中使用某种数据结构的方法吗?谢谢!

1 个答案:

答案 0 :(得分:0)

我在my blog的O(n)时间内用循环链表解决了这个问题。该网站还具有使用队列的O(n)解决方案和使用普通(非圆形)链表的O(n ^ 2)解决方案。使用循环链接列表,您总是向前移动,而不是向后移动,就像您建议使用双向链接列表一样。

举个例子,看看你的清单。从0开始,计数3,删除项目3.然后计数3并删除0.然后计数3并删除4.然后计数3并删除2.然后计数3并删除5.最后计数3并删除1.总计采取的步数是kn,其中n是节点数,k是步长。但这是节点数量的O(n),因为n是问题大小,k是常数。