有n个人围成一个圈依次报数,报到m的人就退圈,下一个人从1在开始报,直到只剩一人,求留下的最后一个人是原本号码是几号?
这是约瑟夫问题(有时也称为约瑟夫斯置换,是一个计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”。)
1.第一版
代码如下:
public static int getBack(int n,int b){
LinkedList<Map<Integer,Integer>> linkedList =new LinkedList<Map<Integer,Integer>>();
//先定义数组,将数据保存到数组中
for (int i=1;i<=n;i++){
Map<Integer,Integer> map = new HashMap<Integer,Integer>(16);
int value= i%b;
map.put(i,value);
linkedList.add(map);
}
int size =linkedList.size();
while(size>1){
Integer newLastMap = (Integer) linkedList.getLast().keySet().toArray()[0];
//挑选出报数为b的人
for (int i =0;i<size;i++){
Map<Integer, Integer> poll = linkedList.poll();
int key = (Integer) poll.keySet().toArray()[0];
if (poll.get(key)!=0){
linkedList.add(poll);
}
}
size = linkedList.size();
// 将队列中的元素重新赋值排序
Map<Integer,Integer> lastMap = linkedList.getLast();
Integer lastKey = (Integer) lastMap.keySet().toArray()[0];
int lastValue = lastMap.get(lastKey);
//TODO 此处有BUG,如果最后一位数为0的时候,在上边会被去除掉,本来20为0,假设2是第一顺位,那么2应该为1,但是此处会变成2是0
int firstValue = (lastValue + 1) % b;
for (int i = 0; i < size; i++) {
Map<Integer,Integer> map = linkedList.poll();
Integer key = (Integer) map.keySet().toArray()[0];
map.put(key, firstValue);
linkedList.add(map);
firstValue = (++firstValue) % b;
}
}
Integer resultKey = (Integer) linkedList.peek().keySet().toArray()[0];
System.out.print("最后留下来的是:");
return resultKey;
}
此处参考的是:
https://www.it610.com/article/1305607963758596096.html
,正如上面説的,我做过测试,发现如果一圈有20个人,报数为7,那么最后留下来的应该是3;但是按上述方法实现,最后留下来的是10;我就打印了一下结果,发现如果最后一个数字19是报的7,那么按照我们定义的那么此时数字19的key为0,下一顺位数字3应该为1,但是实现的结果是数字3也为0。如下所示:
{3=2}
{6=3}
{10=4}
{11=5}
{12=6}
{19=0}
下一轮:
{3=0}
{6=1}
{10=2}
{11=3}
{12=4}
2.第二版
我就按照自己的逻辑修改了以上代码,代码如下:
public static int getNewBack(int n,int b){
LinkedList<Map<Integer,Integer>> linkedList =new LinkedList<Map<Integer,Integer>>();
//先定义数组,将数据保存到数组中
for (int i=1;i<=n;i++){
Map<Integer,Integer> map = new HashMap<Integer,Integer>(16);
int value= i%b;
map.put(i,value);
linkedList.add(map);
}
int size =linkedList.size();
while(size>1){
//先取出最后的key
Integer newLastMap = (Integer) linkedList.getLast().keySet().toArray()[0];
//挑选出报数为b的人
for (int i =0;i<size;i++){
Map<Integer, Integer> poll = linkedList.poll();
int key = (Integer) poll.keySet().toArray()[0];
if (poll.get(key)!=0){
linkedList.add(poll);
}
}
size = linkedList.size();
// 将队列中的元素重新赋值排序
Map<Integer,Integer> lastMap = linkedList.getLast();
//将数字为0的移除后,在取出最后的数字
Integer lastKey = (Integer) lastMap.keySet().toArray()[0];
int lastValue = lastMap.get(lastKey);
int firstValue=0;
//将newLastMap与lastKey比较,看看是否相等
if (newLastMap != lastKey ){
firstValue = ( lastValue +2) % b;
}else {
firstValue = (lastValue + 1) % b;
}
for (int i = 0; i < size; i++) {
Map<Integer,Integer> map = linkedList.poll();
Integer key = (Integer) map.keySet().toArray()[0];
map.put(key, firstValue);
linkedList.add(map);
firstValue = (++firstValue) % b;
}
}
Integer resultKey = (Integer) linkedList.peek().keySet().toArray()[0];
return resultKey;
}
总结
关于报数退圈的实现方法有多种,看看前辈们怎么写的,进行实现,对自己有所帮助就好。