我想在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
你能帮助我吗?该代码有什么问题?
答案 0 :(得分:1)
您正尝试删除索引2
处的项目,但您已删除该项目。
Python索引从 0 开始,而不是从1开始,因此2
是第三个项。换句话说,列表[1, 2]
的长度大于1(有2个项目),但该列表中只存在索引0
和1
。
您可以在循环中添加打印以查看发生的情况:
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 * k
,0 + 1 * k
和0 + 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