Algorithm O(n)中使用循环列表的Josephus问题

Algorithm O(n)中使用循环列表的Josephus问题,algorithm,data-structures,josephus,Algorithm,Data Structures,Josephus,我最近偶然发现了一个论坛,声称Josephus问题可以用一个数据结构在O(n)中解决。这里的明确选择是循环链表,但我声称它只能在O(kn)或O(n^2)中完成,除非你在维基百科中使用数学递归/迭代约瑟夫算法。首先,循环链表具有以下属性:搜索O(n)、删除O(1)、追加O(1)。这假设delete是一个给定的节点,append将替换head或tail 如果我们有一个循环的节点列表,我们可以从起点找到要删除的节点,如下所示: n=6个节点 k=每3个节点删除一次 起始点:节点#0 节点:0、1、2、

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

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

n=6个节点

k=每3个节点删除一次

起始点:节点#0

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

我们可以通过(k+起始点-1)%n计算要删除的节点。对于startpoint=0,我们有(3+0-1)%6=2。现在,3将是我们的出发点。(3+3-1)%5=0,移动时为原始的5节点(即,由于原始的2已消失,数字现在为0,1,2,3,4)。这就是数学版本的基本原理。对于链表,我们可以导出需要删除的节点。问题是我们必须到达这个节点。链表有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)中的数据结构来实现这一点。wikipedia上的解决方案是O(n)中一种非常优雅的数学方法,它显示了递归的威力(纯粹通过调用堆栈跟踪旧的起点,等等),但是当删除实际对象时,似乎不可能得到O(n)。我想展示我试图弄明白这一点的尝试,而不仅仅是明目张胆地问,那么有人知道用O(n)和一些数据结构实现这一点的方法吗?谢谢

我用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是常数。

我想我认为k不是常数。K不是可以在函数中硬编码的东西。换句话说,函数是deleteNodes(节点n,int k)而不是deleteNodes(节点n)。有人可能会说,“如果我使k=3,4,5…1000?1000000,哪个节点会存在?”这仍然是O(kn)。然而,如果面试官认为k是一个常数,那么它就是一个常数哈哈。谢谢你的回答!