约瑟夫环问题

偶然看到一个题目:
N个人围成一圈(0~n-1),从第一个人开始报数,报到m(m-1)的人出圈,剩下的人继续从出圈的下一个人开始报数,报到m(m-1)的人出圈;如此往复,直到所有人出圈。(模拟此过程,输出出圈的人的序号)
第一眼看过去,大概感觉会是找规律的题目,

直观方法

首先想到的是,每次在出圈的人后面到末尾补上前面的人,比如N = 5, m = 3
1,2,3,4,5
第一次3出圈,然后在5后面补上前面的数字,变成1,2 ,3 ,4,5,1,2,
再从4开始,依次这样,但是发现实现起来有点困难,效率有点低。
再想了下,为什么要去移动前面的到后面,而不是直接跳到前面,然后又想了想怎么跳到前面的下标去。
这时候突然想到hashMap中利用hash获得table[]数组下标的方法,对,就是(n-1)&hash,&需要n-1是2的幂,那不需要n-1是2的幂来得到下标的是什么?(不得不说源码的各种奇淫技巧还是很有用的)
答案就是%,取模运算。
然后赶紧试了下

利用模运算

回到上面的问题,3出圈后,变成了1,2,4,5,从4开始,根据模运算,下次出圈的人下标应该为
(4的下标,暂时设为index = 2)
(index + m-1) % length ,算了下,果然不出意外的等于0,也就是编号为1的人,这样可以得到一个很清晰的思路了

  1. 起始位置index = 0,每次出圈的编号为(index + m-1) % length
  2. 更新index = (index + m-1) % length,并出圈当前index的人,长度减1更新length
  3. 当剩下人数不为1时,重复1,2
    所以有:
ArrayList<Integer> list = new ArrayList<>();
for (int i=0; i<n; i++){
	list.add(i);
}
int index = 0;
while (list.size() != 1){
	index = (index + m-1) % list.size();
	list.remove(index);
	System.out.println(list);
}

后面觉得这样的题目肯定里面含有某种规律的,因为实在是太明显了,不过一时没推出来,然后百度了下,发现这是

约瑟夫环问题

借用https://blog.csdn.net/u011500062/article/details/72855826的图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值