46 孩子们的游戏
题目描述
每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的"名侦探柯南"典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?
解题思路
核心思想:约瑟夫环问题。
方法一:模拟
核心思想:使用列表模拟圆圈。
方法二:数学公式
核心思想:递推公式:f(n, m) = (f(n-1, m) + m) % n
时间复杂度:O(n) 空间复杂度:O(n)(模拟)或 O(1)(数学)
Python 实现
python
# 方法一:模拟
def last_remaining_simulation(n, m):
"""
约瑟夫环问题(模拟)
"""
if n < 1 or m < 1:
return -1
people = list(range(n))
index = 0
while len(people) > 1:
index = (index + m - 1) % len(people)
people.pop(index)
return people[0]
# 方法二:数学公式
def last_remaining(n, m):
"""
约瑟夫环问题(数学公式)
"""
if n < 1 or m < 1:
return -1
result = 0
for i in range(2, n + 1):
result = (result + m) % i
return result
# 测试代码
if __name__ == "__main__":
test_cases = [
(5, 3),
(10, 3),
(6, 7),
]
for n, m in test_cases:
print(f"n={n}, m={m} → 最后剩下: {last_remaining(n, m)}")
# 输出:
# n=5, m=3 → 最后剩下: 3
# n=10, m=3 → 最后剩下: 0
# n=6, m=7 → 最后剩下: 4图解
约瑟夫环: n=5, m=3
初始: [0, 1, 2, 3, 4]
[0, 1, 2, 3, 4], index=2, 删除2
[0, 1, 3, 4], index=0, 删除0
[1, 3, 4], index=2, 删除4
[1, 3], index=0, 删除1
[3] → 最后剩下: 3
---
数学公式递推:
f(1, 3) = 0
f(2, 3) = (0 + 3) % 2 = 1
f(3, 3) = (1 + 3) % 3 = 1
f(4, 3) = (1 + 3) % 4 = 0
f(5, 3) = (0 + 3) % 5 = 3