约瑟夫问题 Josephus problem
又叫丢手绢问题,N个人围成一圈,第K个人从1开始报数,数到M的人出圈,后一人接着从1开始报数,直到最后剩下一个。例如N=5,K=1,M=2,出圈的顺序是:2,4,1,5,3
基本思路:
- 将最开始环形链表的第一位命名为first,并定义另一个指针helper帮助计算,helper指向最开始环形链表的最后一位。
- first 和 helper 一起向前移动,每一次循环中被first指向的节点出圈
- 直到最终 helper = first,说明只剩下最后一个节点
遍历法代码如下:
//定义Node3,每一个Node就是一个节点
class Node3 {
// 节点序号
private int no;
// 下一个节点
private Node3 next;
// 构造节点
public Node3(int no) {
this.setNo(no);
}
public Node3 getNext() {
return next;
}
public void setNext(Node3 next) {
this.next = next;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
}
//利用单向链表创建一个环形链表
class CLinkedList {
// 创建一个first节点
private Node3 first = null;
// 添加 n 个节点
public void add(int n) {
// 检查 n 是否有效
if (n < 1) {
System.out.println("N is not valid!");
return;
}
Node3 temp = null;
// 创建环形链表
for (int i = 1; i <= n; i++) {
Node3 node = new Node3(i);
if (i == 1) {
first = node;
first.setNext(first); // 形成环
temp = first; // 让 temp 指向第一个节点
} else {
temp.setNext(node);
node.setNext(first);
temp = node;
}
}
}
/**
* 丢手绢游戏 int startNo 表示从第几个小孩开始 int count 表示要数几下 int nums表示开始总共有多少个小孩在圈内
*/
public void play(int startNo, int count, int nums) {
// 先检验数据的有效性
if (first == null || startNo < 1 || startNo > nums) {
System.out.println("Please input the right numbers!");
return;
}
// 创建 helper 变量帮助计算出圈,helper 指向环形链表的最后一位
Node3 helper = first;
while (true) {
if (helper.getNext() == first) {
break;
}
helper = helper.getNext();
}
// 如果不是从第一位小孩开始,就需要将 first 和 helper 向前移动,让 first 指向开始的小孩
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
// 当小孩开始报数时,first 和 helper 需要移动 count-1 次,然后出圈
// 循环操作直到还剩最后一个小孩
while (true) {
// 当 helper 和 first 向遇,证明只剩最后一个小孩
if (helper == first) {
break;
}
// first 和 helper 向后移动 count+1 位
for (int i = 0; i < count - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
// first 指向的小孩出圈
System.out.println("第" + first.getNo() + "个小孩出圈");
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后留在圈中的小孩是第" + first.getNo() + "个");
}
相关章节
第一节 简述
第二节 稀疏数组 Sparse Array
第三节 队列 Queue
第四节 单链表 Single Linked List
第五节 双向链表 Double Linked List
第六节 单向环形链表 Circular Linked List
第七节 栈 Stack
第八节 递归 Recursion
第九节 时间复杂度 Time Complexity
第十节 排序算法 Sort Algorithm
第十一节 冒泡排序 Bubble Sort
第十二节 选择排序 Select Sort
第十三节 插入排序 Insertion Sort
第十四节 冒泡排序,选择排序和插入排序的总结
第十五节 希尔排序 Shell’s Sort
第十六节 快速排序 Quick Sort
第十七节 归并排序 Merge Sort