码迷,mamicode.com
首页 > 其他好文 > 详细

圆圈中最后剩下的数字

时间:2020-03-30 23:39:29      阅读:114      评论:0      收藏:0      [点我收藏+]

标签:时间复杂度   示例   个数   str   灵活   映射   推导   问题   元素   

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。

圆圈中最后剩下的数字

标签:时间复杂度   示例   个数   str   灵活   映射   推导   问题   元素   

原文地址:https://www.cnblogs.com/olajennings/p/12601844.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!