"约瑟夫环"问题

"约瑟夫环"问题

约瑟夫环:在罗马人占领乔塔帕特后,39 个犹太人与 Josephus 及他的朋友躲到一个洞中,39 个犹太人决定宁愿死也不要被敌人抓到,于是决定了一种自杀方式,41 个人排成一个圆圈,由第 1 个人开始报数,报数到 3 的人就自杀,然后再由下一个人重新报 1,报数到 3 的人再自杀,这样依次下去,直到剩下最后一个人时,那个人可以自由选择自己的命运。这就是著名的约瑟夫问题。现在请用单向环形链表得出最终存活的人的编号。

  首先设置一个长度为n的数组,默认初始化为false,若当前数组中的元素的值为false,说明该元素还未被移除,若当前数组中的元素为true,先将sum++,此时就需要对当前用于计数的sum与m值进行比较,如果sum==m,说明当前位置上的值需要被设置为true(表示该元素已被移除),并将sum重新设置为0,淘汰人数pass+1,若sum!=m,说明此时的sum还不到m,因此将i++,继续判断即可。若当前元素是false,说明当前元素已被移除,直接i++找后一个即可,循环的退出条件是当pass淘汰的人数=总人数(pass<n),此时最终返回的i即为最后一个人所处的编号。
  由于在每次sum++后的值与m进行判断,如果相同会将当前i位置上的元素设置为true,再将i++,因此当前i位置上对应最终返回的其实是i+1,这也就将数组的下标与编号(从0开始)一一对应起来。当最后一个元素返回时,其返回的i并不是下标,而是下标+1.也就刚好是编号的值。


/**
 * Created by xiaoaxiao on 2019/11/27
 * Description: n个人,报到m出去,最后剩下的那个人的编号(从1开始)
 * 			时间复杂度:O(n²)		空间复杂度:O(n)
 */
public class JosephRing {

    public static int getResult(int n, int m) {
        // 设置一个数组表示这些人是否存活
        // 先假设这n个人都活着(false)
        boolean[] people = new boolean[n];
        // 设置当前的编号(1-m)
        int sum = 0;
        // 已经被淘汰了多少人
        // 通过这个已被淘汰的人和总人数的比值,进行循环的退出
        int pass = 0;
        // 定义一个i表示当前数组的下标
        int i = 0;
        while (pass < n) {
            if (i == n) {  // 需要对该数组进行循环遍历,因此当i==n时,将i设置为0
                i = 0;
            }
            if (!people[i]) { // 若当前位置上的人还没有被淘汰
                sum++;
                // 若此时sum==m,说明当前这个位置上报的数就是m
                // 先++再比较,因为sum是从0开始计数的
                if (sum == m) {
                    // 淘汰的人+1
                    pass++;
                    // 该位置被设置为true,意味着该位置已被淘汰
                    people[i] = true;
                    // 将sum重新设置为0,进行下一轮的约瑟夫过程
                    sum = 0;
                }
                // 无论当前位置上的人是否被淘汰,i都需要向后走一步
                // 比较巧妙:如果是最后一次pass==n时,此时的i再+1,刚好对应了实际的编号(从1开始)
                i++;
            } else { // 若当前位置上的人已经被淘汰了,直接i++往后走就行
                i++;
            }
        }
        return i;
    }
}

发布了119 篇原创文章 · 获赞 24 · 访问量 1万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章