• 有1到100共100个数, 从1开始, 每隔1, 2, 3... 个数拿走一个数, 最后剩下几?(约瑟夫环)


    最近找实习, 在做Test Assignment时遇到了这么道题, 就顺便记录下来:
    说, 有1到100共100个数, 摆成一个圈. 从1开始, 每隔1, 2, 3, 4 ... 个数拿走一个数, 一直循环, 最后剩下几? 具体的讲就是一开始(隔0个数)把 1 拿走, 隔1个数(2)把3拿走, 再隔2个数(4, 5)把6拿走, 再隔3个数(7, 8, 9)把10拿走. 第一圈数到100之后接着从2开始数, 直到最后剩下1个数为止, 请问最后剩下几? 如果是1到n呢?

     1     public static int selectNumber(int n) {
     2         
     3         int result = -1;
     4         ArrayList<Integer> nums = new ArrayList<Integer>();
     5         int index = 0;     // this variable is used to remove numbers from list 
     6         int count = 0;     // count is used to count which numbers should be remove
     7         int pIndex = 0;  // this is used to record previous index
     8         
     9         // generate a list contains numbers from 1 to n
    10         for(int i = 1; i <= n; i++) {
    11             nums.add(i);
    12         }
    13         
    14         while(nums.size() > 1) {
    15             
    16             while(index < nums.size()) {
    17                 nums.remove(index);     
    18                 count++;
    19                 pIndex = index;
    20                 index += count;
    21             }
    22             
    23             index = count - (nums.size() - pIndex);
    24             
    25             while(index > nums.size() - 1) {
    26                 index = index - nums.size();
    27             }
    28         }
    29         
    30         result = nums.get(0);
    31         return result;
    32     }
    33     
    34     public static void main(String[] args) {
    35         int surviver = selectNumber(100);
    36         System.out.println("The surviver is: " + surviver);
    37     }

    以上就是我的解决方案, 最后留下的数是31


    2016.06.04更新:

    在我发布这篇博文之后热心网友指出这叫"约瑟夫环". 于是我就去网上搜了一下, 并找到了一个比较简洁的约瑟夫环代码(这个代码不是我原创, 是在别人代码的基础上修改得来):

     1     /**
     2      * 约瑟夫环:
     3      * n个数字摆成一个环, 从1开始数, 数到m或m的倍数的数字被删除, 然后继续, 直到剩下1个数字为止
     4      */
     5     public static int josephProbBasic(int n, int m) {
     6         ArrayList<Integer> list = new ArrayList<>();
     7         for(int i = 1; i <= n; i++) {
     8             list.add(i);
     9         }
    10         // 用于计数
    11         int count = 1;
    12         // 当list中只剩下1个数时, 结束循环
    13         for(int i = 0; list.size() > 1; i++) {
    14             // 如果数到list的结尾, 从0开始重新数
    15             if(i == list.size()) {
    16                 i = 0;
    17             }
    18             // 在m的倍数时, 删除对应的数
    19             if(count % m == 0) {
    20                 // 由于删除之后, list中被删除元素之后的元素都会依次向前移动一位, 因此也要把i向前移动一位
    21                 list.remove(i--);
    22             }
    23             count++;
    24         }
    25         return list.get(0);
    26     }

    但是这只是普通的约瑟夫环, 而我的问题要更麻烦一点. 于是乎, 我根据上面的思路重写了这个问题的代码:

     1     /**
     2      * 升级版约瑟夫环:
     3      * n个数字摆成一个环, 从1开始数, 每隔m个数字删除一个数字. m的初始值为0, 然后m++, 就是0, 1, 2, 3....
     4      *  这样不断删除, 直到剩下1个数字为止.
     5      * @param n
     6      * @return
     7      */
     8     public static int josephProbV2(int n) {
     9         ArrayList<Integer> list = new ArrayList<>();
    10         for(int i = 1; i <= n; i++) {
    11             list.add(i);
    12         }
    13         int count = 0;
    14         int m = 0;
    15         for(int i = 0; list.size() > 1; i++) {
    16             if(i == list.size()) {
    17                 i = 0;
    18             }
    19             // 如果count数到m个数, 就删除对应的数字, 同时count从零开始重新数, m = m + 1
    20             if(count == m) {
    21                 list.remove(i--);
    22                 count = 0;
    23                 m++;
    24             }else {
    25                 count++;
    26             }
    27         }
    28         return list.get(0);
    29     }

    这样感觉清爽多了. 

  • 相关阅读:
    java8
    java7
    java6
    java5
    java复习4
    学习笔记
    Reflection笔记
    通过Reflection来获得方法和信息
    學習反射2
    學習反射1
  • 原文地址:https://www.cnblogs.com/zhenyu-go/p/5529618.html
Copyright © 2020-2023  润新知