Skip to content

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
最近更新

基于 MIT 许可发布