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

题目来源:牛客

题目描述:

每年六一儿童节,牛客都会准备一些小礼物和小游戏去看望孤儿院的孩子们。其中,有个游戏是这样的:首先,让 n 个小朋友们围成一个大圈,小朋友们的编号是0~n-1。然后,随机指定一个数 m ,让编号为0的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0... m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客礼品,请你试着想下,哪个小朋友会得到这份礼品呢?

 

说明:

本题困扰了我一段时间,因为人的编号是从0开始的,最后一个人是n-1,但是报数却是1,2,3这样的报数,个人因为强迫症而无法理解,在想通后分享给大家

其实看到这道题后,大家都能想到一个叫做环形队列的东西,思路就是这个的扩展,下面我们来讨论别的解决方法

方法一

int LastRemaining_Solution(int n, int m) {
        queue<int> q;
        for(int i=0;i<n;i++)
        {
            q.push(i);
        }
        while(q.size()>1)
        {
            for(int i=0;i<m-1;i++)
            {
                q.push(q.front());
                q.pop();
            }
            q.pop();
        }
        return q.front();
    }

 思路:我们使用队列,输入n和m,有n个数据,将数据从0到n-1全部先入队列(因为是0开头,所以最后是n-1),然后我们开始删除元素,只要剩余元素数量大于1,我们就一直删,我们要删除的是第m个元素,报数是从1开始,是1,2,3,...,m,我们把队列的前m-1个元素按顺序移动到队列尾部,此时队列头部的元素就是第m个元素,也就是我们需要删除的元素,这样循环即可

方法二(重点)

int LastRemaining_Solution(int n, int m) {
        if(n<=0)
            return -1;
        int p = 0;
        for(int i=1;i<=n;i++)
        {
            p = (p+m)%i;
        }
        return p;
    }

下面我们来看这种思路,这里我们举例子说明,n=5,m=3

我们假设此时报数已经结束,只剩最后一个元素,按顺序被删掉的元素是2,0,4,1,此时剩余的元素是3,因为只剩一个元素,所以标号是0,此时我们进行倒推

在只剩2个元素时,是1,3,编号是0,1

在只剩3个元素时,是1,3,4,编号顺序为0,1,2

4个元素时,是3,4,0,1

5个元素时,是0,1,2,3,4

我这里的排列顺序为删掉元素后,下一位是新的开头,为标号0,比如5个元素时我们删除2,此时3就是新的开头,所以剩余4个元素时,顺序是3,4,0,1

借用方法一的思路,我们可以知道,删除一个元素后,相当于把整个队列向前推进m,我们想,从剩余5个元素开始,我们删除了2,那么3就是新的开头,3就向前移动了m位(3位),其他的跟着走,变成3,4,0,1,我们一直删一直删,删到只剩一个元素,也就是只剩3,那我们每次增加一个元素,让他每次向后移动3位,一直增加到5个元素,最终得到的不就是3的起始位置吗?

我们看代码,p即为我们最终所求结果,p的初始值为0,这是因为我们最终只有3一个元素,编号也就只有0,所以这里初始值为0

p=p+m,这个大家都可以理解,我们每次需要让p向后移动m位

p=(p+m)%i ,以及循环初始值 i 是什么意思?为什么最终是<=n呢?

i 的初始值 i = 1,这代表我们最开始只有一个元素,其他元素都被我们删除了,只剩下3

%i 是为了防止超出界限,想一想,当 i = 2 时,此时我们增加了一个元素,就是1,3,这时候只有两个元素,所以此时 i 是等于2的,因为只有两个元素,所以编号p最大也不可能超过 i (这里就是2),所以要%i

按照这个思路,我们不断增加元素,不断向后移动,当元素数量增加到n时,也就是 i = n时,就可以得到结果,用我们的例子来说,就是3的位置,也是3的编号

如果大家还是不理解,就结合这张图看,其中红色下标线的表示本次要删除的元素,绿色框起来的表示元素不够时,依次循环起来,也就是说,没有框起来的代表本次有多少元素参与,我们的思路是从下往上看,大家自己画一画,就可以轻松理解

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值