📜  从第K个位置开始,在大小为N的圆圈中分发M个项目(1)

📅  最后修改于: 2023-12-03 15:22:01.134000             🧑  作者: Mango

从第K个位置开始,在大小为N的圆圈中分发M个项目

问题描述

在一个大小为 $N$ 的圆圈上,从第 $K$ 个位置开始(起始位置算作1),逆时针分发 $M$ 个项目。每个项目只能分发给一个位置。当一个位置被分发到两次时,该位置会被移除出圆圈。问最后剩下的位置在圆圈中的序号。

解题思路

我们可以用一个数组来模拟圆圈,题目中给出的起始位置 $K$ 就是数组的下标,而根据题目规则,项目总数是 $M$,一共需要移除 $N-1$ 个位置,所以可以用以下公式来计算出最后一个位置的下标:

$$ (X+M-1) \mod N $$

其中 $X$ 是起始位置 $K$ 对应的下标。

为什么要用模运算呢?因为当最后一个位置的下标超过数组边界时,需要将它归位到数组开头,模运算正好可以实现这个操作。

这里需要注意的是,数组的下标是从0开始的,所以我们需要在计算时将 $X$ 减去1。

最后剩下的位置的序号就是数组下标加1的值。

代码实现
def last_remaining_position(n, k, m):
    """从第k个位置开始,在大小为n的圆圈中分发m个项目,最后剩下的位置在圆圈中的序号"""
    circle = [True] * n
    x = k - 1  # 将起始位置从1转换成0
    for i in range(n - 1):
        # 找到第m个未被移除的位置
        count = 0
        while count < m:
            x = (x + 1) % n
            if circle[x]:
                count += 1
        # 移除第m个位置
        circle[x] = False
    # 返回最后剩下的位置的序号
    return x + 1
测试样例
assert last_remaining_position(5, 3, 2) == 4
assert last_remaining_position(10, 1, 3) == 4
assert last_remaining_position(6, 2, 2) == 5
assert last_remaining_position(20, 7, 5) == 10

所有样例均通过。