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

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

题目

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

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

方法一 环形链表模拟圆圈

思路:用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

结果:超时

方法二 环形列表

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

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

代码

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]

结果:超时

方法三 数学

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

第二次从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%的用户

posted @ 2020-03-21 17:53  whiky  阅读(142)  评论(0编辑  收藏  举报