孩子们的游戏(圆圈中最后剩下的数)

题目描述

首先,让小朋友们围成一个大圈。然后随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友获得神秘大奖,。请你试着想下,哪个小朋友会得到这份神秘大奖呢呢?(注:小朋友的编号是从0到n-1)

题解

解法1

模拟环形链表
这里通过取模运算直接算出要删除的位置,简化了寻找的过程

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if(n == 0)  return -1;
        //初始化小朋友们
        vector<int> haha;
        for(int i = 0; i < n; i++){
            haha.push_back(i);
        }
        //进行游戏
        int i = 0;  //上次删除的位置
        while(haha.size() > 1){
            i = (i + m - 1) % haha.size();
            haha.erase(haha.begin() + i);
        }

        return *haha.begin();
    }
};

解法2

定义f(n, m) 表示每次在0到i-1中删除第m个数最后剩下的数。

第一次编号为 k = (m-1)%n 的小朋友出列之后,剩下的n-1个人组成了一个新的约瑟夫环:

k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2并且从k开始报0。

由于这个序列的规律与之前的不一样,记为f’(n-1,m),值与f(n,m)相同。
现在我们把他们的编号做一下转换:

k+1   --> 0
k+2   --> 1
...
...
k-2   --> n-3
k-1   --> n-2

变换后成为了 n-1 个人报数的子问题,其结果为f(n-1,m), 根据映射可求出
f’(n-1,m) = ( f(n-1,m) + k + 1) % n
代入 k = (m-1) % n,
f(n,m) = f’(n-1, m) = ( f(n-1,m) + m) % n。

最终得到递归公式为

f(1, m) = 0;  //终止条件
f(i, m) = (f(i-1,m) + m) % i;  //i>1

代码可选择递归或循环

class Solution {
public:
    int LastRemaining_Solution(int n, int m)
    {
        if(n == 0)  return -1;
        int res = 0;
        for(int i = 2; i <= n; i++){
            res = (res + m) % i;
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值