📌  相关文章
📜  执行给定的操作后,找出卡上最后剩下的数字(1)

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

执行给定的操作后,找出卡上最后剩下的数字

在一张卡上,有数字从0到n-1依次排列。现在对这张卡执行给定的操作,具体操作描述如下:

  1. 从卡上的第一个数字开始,每次删除第m个数字。

  2. 删除的数字不再保留,下一个数字继续从卡的第一个数字开始数。

  3. 重复上述操作,直到卡上只剩下一个数字为止。

你的任务是编写一个函数,返回执行上述操作后,卡上最后剩下的数字。

解题思路

这是一道经典的问题,有多种解法。

我们可以用链表来模拟整个过程。首先把0~n-1的数字放入链表中,然后从头开始遍历链表,每经过m-1个节点就删除它。删除节点后继续从头开始遍历链表,直到链表中只剩下一个节点为止。

也可以用递推公式解决这个问题。如果我们用f(n,m)代表最后留下的数字的下标,那么有下面的递推关系:

f(n, m) = (f(n-1,m) + m) % n

这个公式的意义是,在n个数字中,每次删除第m个数字,最后剩下的数字的位置等于在n-1个数字中删除第m个数字最后剩下的数字的位置再往后移m个位置。这是一个递归的结构,当n=1时,递归结束,方程的解就是0。

代码实现
用链表来模拟
class Node:
    def __init__(self, val=None, next=None):
        self.val = val
        self.next = next

def lastRemaining(n: int, m: int) -> int:
    # 构建链表
    head = Node(0)
    pre = head
    for i in range(1, n):
        node = Node(i)
        pre.next = node
        pre = pre.next
    # 进行删除操作,直到链表中只剩一个节点
    while head.next != head:
        for i in range(m-1):
            head = head.next
        head.next = head.next.next
    return head.val
用递推公式
def lastRemaining(n: int, m: int) -> int:
    f = 0
    for i in range(2, n+1):
        f = (f + m) % i
    return f
总结

不论使用哪种方式,本题都是一道简单的数学题,但需要注意边界条件和细节问题。使用链表来模拟可以避免出现integer overflow的问题,但需要注意内存的消耗。而用递推公式则可以更为简洁地解决问题,但需要考虑清楚每个变量的含义,以免出现错误的递推关系。