如何解决python中的Josephus拼图?

时间:2015-06-05 11:44:30

标签: python

我想在Python中表示Josephus problem。简而言之,给定一个列表items,每个k个元素都被访问/标记,直到没有“未触动”的项目。如何以这种方式遍历列表并查看最后一个未触及的元素是什么?

我的代码是:

def josephus(items,k):
    while len(items)>1:
        del items[k]
    return items

但是,当我试图

print(josephus([1,2,3,4,5,6,7,8,9,10],2))

它返回:

  line 3, in josephus
    del items[k]
IndexError: list assignment index out of range
你能帮助我吗?该代码有什么问题?

3 个答案:

答案 0 :(得分:1)

您正尝试删除索引2处的项目,但您已删除该项目。

Python索引从 0 开始,而不是从1开始,因此2第三个项。换句话说,列表[1, 2]的长度大于1(有2个项目),但该列表中只存在索引01

您可以在循环中添加打印以查看发生的情况:

def josephus(items, k):
    while len(items) > 1:
        print(items)
        del items[k]
    return items

并使用稍短的列表调用该函数以保持输出可管理:

>>> josephus([1,2,3,4], 2)
[1, 2, 3, 4]
[1, 2, 4]
[1, 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in josephus
IndexError: list assignment index out of range

这表示您每次都删除第3个项目,当只剩下2个项目时会抛出错误。

您可以测试的长度大于k

,而不是对长度进行硬编码
def josephus(items, k):
    while len(items) > k:
        del items[k]
    return items

现在循环条件保证索引k处有一个要删除的元素:

>>> def josephus(items, k):
...     while len(items) > k:
...         del items[k]
...     return items
... 
>>> josephus([1,2,3,4], 2)
[1, 2]

然而,从给定的索引开始删除所有内容是很多工作。只需使用切片

def josephus(items, k):
     del items[k:]
     return items

[k:]表示法告诉Python处理从索引k开始直到列表末尾的所有项目(:之后没有值)。

但是,如果你应该删除每个k元素(所以每隔2或3等),那么你就是错误的方式。再次使用切片表示法:

del items[::k]

我填写了切片的 3rd 插槽, stride 。这将删除元素0 + 0 * k0 + 1 * k0 + 2 * k等:

>>> items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> items[::2]
[1, 3, 5, 7, 9]
>>> del items[::2]
>>> items
[2, 4, 6, 8, 10]

如果您尝试实施Josephus problem,则无法使用此项来删除项目,因为删除必须是循环,至少在没有为下一个计算新的起点时淘汰赛。使用%模数运算符绕圈旋转,调整长度变化:

def josephus(items, k):
    skip = k - 1  # deletion removes the item, so skip k - 1
    index = skip % len(items)
    while len(items) > 1:
        del items[index]
        index = (index + skip) % len(items) 
    return items[0]

请注意,我现在返回一个幸存项目,而不是列表。

代码会跟踪index中要删除的 next 项目。我们从k - 1开始调整基于0的索引;第二项是1。然后我们通过递增k - 1个步骤来绕过“圆圈”,因为我们刚删除了k项,之后的所有内容都会围绕圆圈向上移动,并使用%回到列表的开头。

答案 1 :(得分:0)

你需要&gt; K:

 while len(items) > k:

在您尝试索引双元素列表的第三个元素时,错误之前的最后一个值项为[1, 2] items[2]-> IndexError

def josephus(items, k):
    while len(items) > k:
        del items[k]
    return items

输出:

In [27]: josephus([1,2,3,4,5,6,7,8,9,10],2)
Out[27]: [1, 2]

如果您希望2表示第二个索引,则需要从k开始-1:

def josephus(items, k):
    while len(items) >= k:
        del items[k-1]
    return items

现在你会得到一个元素:

In [29]: josephus([1,2,3,4,5,6,7,8,9,10],2)
Out[29]: [1]

要删除k'th元素:

def josephus(items, k):
    if 0 <= k < len(items):
        del items[k]
    return items

答案 2 :(得分:0)

如果要从索引k开始删除原始列表中的每个i值,只需执行

del items[i::k]

在您的具体情况下,您似乎首先要删除项目k,所以:

del items[k-1::k]

这很简单,你不会把它包装在一个函数中,但如果你想:

将其包装在一个函数中:

def josephus(items,k):
    del items[k-1::k]
    return items