圆圈中最后剩下的数字

Posted olajennings

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了圆圈中最后剩下的数字相关的知识,希望对你有一定的参考价值。

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
示例 2:

输入: n = 10, m = 17
输出: 2
 

限制:

1 <= n <= 10^5
1 <= m <= 10^6
通过次数20,094提交次数33,369

 

class Solution {
public:
    int lastRemaining(int n, int m) {
        int ans = 0;
        for(int i =2; i <= n; i++){
            ans = (ans+m)%i;
        }
        return ans;
    }
};

解题思路:

这其实是约瑟夫环问题,可以在剑指offer第300页找到。

这道题如果用循环队列或循环链表来模拟的话,会超时,因为对于每一次删除操作,时间复杂度都是O(n),一共要进行m次,那时间复杂度就是O(mn),而且还要开一个O(n)的空间存储数据。

这道题正确的做法应该是使用数学方法:
关于证明方法的话,可以参考剑指offer第300页,推导的关键是灵活使用 x = a%n => k*n + x = a这条公式,以及求映射p(x)的逆函数。

归纳的话:

因为每次都会从头开始找到第m个数,然后将其删除。

删除后,把其后面的那个数移动到最前面去,然后接着重复一删-移的过程。

所以我们走到最后,剩下一个元素的时候,他就是我们的答案了。

然后我们可以从最后一个元素反过来往前推导。

最后剩下一个元素的时候,这个元素怎么来的?

在剩下两个元素的时候,删掉另外一个,然后把它往前移动m个位置,它是这么来的。

所以我要复原原本的位置,那就当前位置加上m咯!

假设当前位置是idx,那么还剩两个元素的时候的位置就是idx+m

但要注意这玩意是循环的,所以idx+m可能超过长度2了,所以我们要多2取模

所以在剩下2个元素的时候,它的位置是 (idx+m)%n,其中n=2

这样就形成了递推公式: idx= (idxn-1 + m)% n

所以我们从n=2的时候开始往n计算,特别地,idx = 0。

以上是关于圆圈中最后剩下的数字的主要内容,如果未能解决你的问题,请参考以下文章

约瑟夫环(超好的代码存档)--19--约瑟夫环--LeetCode面试题62(圆圈最后剩下的数字)

约瑟夫环(超好的代码存档)--19--约瑟夫环--LeetCode面试题62(圆圈最后剩下的数字)

LeetCode刷题-圆圈中最后剩下的数字

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

圆圈中最后剩下的数字

圆圈中最后剩下的数字