Josephus Permutation(约瑟夫排序)

问题

这个问题的由来还是很有趣的,有一个叫约瑟夫的历史学家和40个士兵被罗马军队围困在一个洞穴中,他们拒绝投降而选择了自杀。这个自杀的方式还是很有创意的。41个人站成一个圈,从某个人开始,这个人将会杀死从他开始顺时针数到的第k个人,剩下的人接着数,最后就剩一个人,那个人自杀。死人的顺序就是约瑟夫排序。
现在给出一个初始化数组t,和每次数人的个数k,要求返回约瑟夫排序的结果。

例子

[1,2,3,4,5,6,7] - initial sequence
[1,2,4,5,6,7] => 3 is counted out and goes into the result [3]
[1,2,4,5,7] => 6 is counted out and goes into the result [3,6]
[1,4,5,7] => 2 is counted out and goes into the result [3,6,2]
[1,4,5] => 7 is counted out and goes into the result [3,6,2,7]
[1,4] => 5 is counted out and goes into the result [3,6,2,7,5]
[4] => 1 is counted out and goes into the result [3,6,2,7,5,1]
[] => 4 is counted out and goes into the result [3,6,2,7,5,1,4]

我的代码

package codewars;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Josephus {
    static class Node {
        Object value = 0;
        Node next = null;

    }
    public static <T> List<T> josephusPermutation(final List<T> items, final int k) {
        List<T> result = new ArrayList<T>();
        // 如果为空或只有一个元素,那么直接返回
        if (items.size() <= 1)
            return items;
        // 保存第一个节点,用于让最后一个节点指向它,从而构成循环列表
        Node head = new Node();
        // 指向当前元素的指针
        Node pointer = null;
        // 指向前一个元素指针,主要用于删除链表的节点
        Node pre = null;
        // 构建单向循环链表
        for (int i = 0; i < items.size(); i++) {
            if (i == 0) {
                head.value = items.get(i);
                pointer = head;
            } else {
                Node node = new Node();
                node.value = items.get(i);
                pointer.next = node;
                pointer = pointer.next;
            }
        }
        pointer.next = head;

        // 开始取数据
        while (pointer.next != null) {
            for (int j = 0; j < k; j++) {
                pre = pointer;
                pointer = pointer.next;
            }
            result.add((T)pointer.value);
            pre.next = pointer.next;
            pointer = pre;
            if (pointer == pointer.next) {
                pointer.next = null;
            }

        }
        result.add((T)pointer.value);
        return result;
    }

    public static void main(String[] args) {
        List result = josephusPermutation(Arrays.asList(new Object[]{"C"}), 4);
        System.out.println(result);
    }
}

别人的代码

import java.util.ArrayList;
import java.util.List;
import java.util.Collection;

public class Josephus {
  public static Collection<Object> josephusPermutation(final List<Object> items, final int k) {
    Collection<Object> permutation = new ArrayList<Object>();
    int position = 0;
    while(items.size() > 0) {
      position = (position + k - 1) % items.size();
      permutation.add(items.remove((int) position));
    }
    return permutation;
  }
}

分析

我选择先将数组构建成一个循环列表,再不断循环取数据。别人的代码就显得比较简单,直接用取模的方式。List.remove 这个方法不但能删除元素,还会返回被删除的元素。这种取模的方法我也考虑过,就是比较担心如果是传入的参数是ArrayList的话,删除元素的性能会比较差,所以才构建了链表。

猜你喜欢

转载自blog.csdn.net/qqqq0199181/article/details/80785826