约瑟夫环(Joseph Ring)
约瑟夫环起源于一段残酷的历史故事。据说是在古罗马人占领乔塔帕特这个地点后,39 个犹太士兵与约瑟夫将军及他的朋友决定宁死不降,于是约瑟夫想出了一种自我了结的方式。即41个人围成一个圆圈,由第1个人开始报数,每报数到第3人,该人就出局自我了结,然后再由下一个重新报数,直到所有人都了结为止。但约瑟夫和他的朋友却想苟活,他便将朋友与自己安排在第16个与第31个位置,最终剩下他们二人便投降了。
约瑟夫环抽象概念:有从 1 至 n n n 个编号围成一圈。从 1 到 m ( m ⩽ n ) m(m \leqslant n) m(m⩽n),凡数到 m m m 的编号退出圆圈,直到仅剩 r ( r > m ) r(r > m) r(r>m) 个编号为止。然后求被排除的编号。
数组实现约瑟夫环
class JosephRingArray:
def __init__(self, total: int, out: int, rest: int):
self.total = total
self.out = out
self.rest = rest
self.data = list(range(1, total + 1))
def get_out_list(self) -> list:
index = 0
result = []
circle = self.data
while len(circle) > self.rest:
index += self.out - 1
if index >= len(circle):
index -= len(circle)
result.append(circle.pop(index))
return result
if __name__ == "__main__":
print("数到9的编号的出列顺序:", JosephRingArray(20, 9, 15).get_out_list())
链表实现约瑟夫环
class ListNode(object):
def __init__(self, value, next=None):
self.value = value
self.next = next
class JosephRing:
def __init__(self, total: int, out: int, rest: int):
self.total = total
self.out = out
self.rest = rest
self.head = ListNode(1)
# 构建循环链表
p = self.head
for i in range(2, total + 1):
p.next = ListNode(i)
p = p.next
p.next = self.head
def get_out_list(self) -> list:
result = []
p = self.head
out = 1
while self.total > self.rest:
prev: ListNode = p
p = p.next
out += 1
if out == self.out:
result.append(p.value)
prev.next = prev.next.next
out = 0
self.total -= 1
return result
if __name__ == "__main__":
print("数到9的编号的出列顺序:", JosephRing(20, 9, 15).get_out_list())
终端输出结果
数到9的编号的出列顺序: [9, 18, 7, 17, 8]