剑指offer-62.圆圈中最后剩下的数字(约瑟夫问题)★

题目来源:https://leetcode-cn.com/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/

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

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

 

示例 1:

输入: n = 5, m = 3
输出: 3

限制:

  • 1 <= n <= 10^5
  • 1 <= m <= 10^6

思路:

由于n和m的范围都很大,如果用循环链表来做会超时。这实际上是一个约瑟夫问题:

N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。

约瑟夫问题是有数学解的,设f(n,m) 表示n个数、不断删除第m个数、最后剩下的数字,则有:

f(n,m)=(f(n-1,m) + m)\mod n

推导过程:

Q1:假设已经知道n=11、m=3时,最后胜利的人的下标为6,那么n=10、m=3时,最后胜利的人的下标?

A1:第一次删去第m个人后,从第m+1个人开始重新标号,所以所有人的标号都减少了m(取mod来满足循环)。

Q2:假设已经知道n=10、m=3时,最后胜利的人的下标为3,那么n=11、m=3时,最后胜利的人的下标?

A2:第一个问题的逆过程,所以所有人的标号都增加了m(同样取mod来满足循环)

Q3:扩展到任意情况,人数为n、删除报到m的那个人,那么最后胜利的人的下标是怎么移动的?

A3:从n=2开始逐层递推,f(3)=(f(2)+m)%3,f(4)=(f(3)+m)%4,f(5)=(f(4)+m)%5......f(n)=(f(n-1)+m)%n

代码:

class Solution(object):
    def lastRemaining(self, n, m):
        """
        :type n: int
        :type m: int
        :rtype: int
        """
        last = 0
        for i in range(2, n+1):
            last = (last + m) % i
        return last

参考:

https://blog.csdn.net/u011500062/article/details/72855826

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值