[剑指offer]62.圆圈中最后剩下的数字

62.圆圈中最后剩下的数字

题目python

0,1,...,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。指针

例如,0、一、二、三、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是二、0、四、1,所以最后剩下的数字是3。code

方法一 环形链表模拟圆圈

思路:用head找要被删除的元素,用temp的指针指向head。当找到该元素时,令head=head.next,temp.next=head将该元素删除。内存

class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        head = temp = ListNode(0)
        for i in range(1, n):
            temp.next = ListNode(i)
            temp = temp.next
        temp.next = head
        while temp.next != temp:
            for i in range(m-1):
                head = head.next
                temp = temp.next
            head = head.next
            temp.next = head
        return temp.val

结果:超时rem

方法二 环形列表

思路:与链表相似,本身定义一个列表arr=[0, 1, ..., N-1],每次从i开始计数,数到第m个值将其删除。最后返回列表中仅存的元素。数学

用%操做使得列表循环遍历。io

代码ast

class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        arr = [i for i in range(n)]
        i = 0
        size = n
        while size > 1:
            del_index = (i+m-1) % size
            arr.remove(arr[del_index])
            size -= 1
            i = del_index
        return arr[0]

结果:超时class

方法三 数学

思路:设从0开始计数,共n我的,数到m个依次出局,最后剩下的人编号设为f(n,start=0)。第一次出局的人编号为(m-1)%n,记为k。List

第二次从k+1开始数,即f(n-1, start=k+1)=f(n, start=0)。

又由于f(n-1, start=k+1)=(f(n-1, start=0)+k+1)%n。

有f(n-1, start=k+1)这个中间桥梁,能够推出f(n, start=0)=(f(n-1, start=0)+k+1)%n。即 (f(n)=f(n-1)+m)%n.

代码

class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        if n < 1 or m < 1:
            return None
        res = 0
        for i in range(2, n+1):
            res = (res + m) % i 
        return res

结果

执行用时 :84 ms, 在全部 Python3 提交中击败了82.30%的用户 内存消耗 :13.6 MB, 在全部 Python3 提交中击败了100.00%的用户

相关文章
相关标签/搜索