约瑟夫问题描述如下:约瑟夫问题
解题思路如下:
用单循环链表模拟犯人,链表中的每一个节点代表一个犯人。假设总共有 n 个犯人,每隔 m 个犯人处决一个,起始位置是 k,那么从第 k 个节点开始遍历,遍历到第 m+1 个节点时,移除该节点。然后再从 1 遍历到 m+1……如此循环往复,直到只剩下一个节点,就是幸存的犯人。
代码如下:
/**
* 约瑟夫问题
* filename: JosephusProblem.java
*/
public class JosephusProblem {
/**
* 约瑟夫问题的解决方案
* @param len 总人数
* @param num 要跳过的人数
* @param start 开始的位置
*
*/
public static void solution(int len, int num, int start){
if(start < 1 || start > num)
return;
MyLinkedList mll = new MyLinkedList();
mll.createCycleList(len);
Node cur = mll.getHead(); //当前节点
Node pre = null; //当前节点的上一个节点
for (int i = 1; i < start; i++){ //定位到起始位置
pre = null;
cur = cur.next;
}
while (mll.getSize() > 1){
for (int i = 0; i < num; i++){
pre = cur;
cur = cur.next;
}
System.out.println("杀死 "+ cur.val + " 号犯人");
cur = mll.remove(pre, cur);
}
System.out.println();
System.out.println("最后存活的是 " + cur.val +" 号犯人");
}
}
class Node{
public int val;
public Node next;
public Node(int val) {
this.val = val;
this.next = next;
}
}
class MyLinkedList{
private Node head;
private Node tail;
private int size;
/**
* 创建循环链表
* @param len 链表中元素的个数
*/
public void createCycleList(int len){
if(len < 1)
return;
head = new Node(1);
tail = head;
for (int i = 1; i < len; i++){
Node node = new Node(i+1);
tail.next = node;
tail = node;
}
tail.next = head;
size = len;
}
public Node getHead(){
return head;
}
public int getSize(){
return size;
}
/**
* 删除结点
* @param pre 要删除的结点的前一个结点
* @param cur 要删除的结点
* @return 返回的是 cur 指向的新的引用
*/
public Node remove(Node pre, Node cur){
cur = cur.next;
pre.next.next = null;
pre.next = cur;
size--;
return cur;
}
}
然后创建一个 Main 类调用 JosephusProblem 类。
/**
* 主类
* filename: Main.java
*/
public class Main {
public static void main(String[] args) {
JosephusProblem.solution(10, 4, 2);
}
}
时间复杂度是 O ( n × m ) O(n\times m) O(n×m),空间复杂度是 O ( n ) O(n) O(n)。