剑指Offer——面试题45:圆圈中最后剩下的数字

圆圈中最后剩下的数字


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

输入:5,3

输出:3

两个解法:第一个、是经典的解法,用环形链表模拟圆圈

第二个、分析每次被删除的数字的规律,利用动态规划解决问题

思路:下面,我们主要介绍,用动态规划来解决问题的方式。
1、首先,我们定义一个关于n、m的方程:f(n,m),该方程表示在n个数字中每次删除第m个数字最后剩下的数字
根据1中的定义,我们可知 f(n-1,m)表示在n-1个数字中每次删除第m个数字最后剩下的数字。那么f(n,m) 与 f(n-1,m) 有什么关系呢?
我们可以想到在n个数字中删除第m个数字后,那么n个数字就变成了n-1个数字,只是这n-1个数字是从 m , m+1…n-1, 0, 1,…m-2。于是,我们就想可不可以将 f(n,m) 在删除第m个数字后,进行映射,将上述{m , m+1…n-1, 0, 1,…m-2}映射成{0, 1, 2, … n-2}
2、于是,我们构建一个映射,将{m , m+1…n-1, 0, 1,…m-2}映射成{0, 1, 2, … n-2},很容易想到p(x) = (x-m)%n,那么该映射的逆映射就是(x+m)%n
3、于是,就将 f(n,m) = [ f(n-1,m) + m ] % n (n>1),当n=1时,f(n,m)=f(n-1,m)=0,联系起来,即递归式写出来了

/*
思路:利用动态规划,找出f(n,m)与f(n,m-1)的递推关系,然后编程即可
     f(n,m)的值表示n个数字中每次删除第m个数字,删除第m个数字后,从m+1开始计数,最终剩下的那个数字
*/
class Solution {
public:
    /*
    这是递归的做法
    */
    int LastRemaining_Solution(int n, int m)
    {
        if(n<1){
            return -1;
        }
        if(n==1){
            return 0;
        }
        return (LastRemaining_Solution(n-1,m) + m ) % n;
    }

    /*
    这是循环的做法
    */
    int LastRemaining_Solution(int n, int m)
    {
        if(n<1){
            return -1;
        }
        if(n==1){
            return 0;
        }
        int remainNumber=0;
        for(int i=2;i<=n;i++){
            remainNumber=( remainNumber + m )%i;
        }
        return remainNumber;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值