报数退圈--java实现


有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;
    }

总结

关于报数退圈的实现方法有多种,看看前辈们怎么写的,进行实现,对自己有所帮助就好。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值