问题描述:编号为1-N的N个士兵围坐在一起形成一个圈,从编号为1的士兵依次开始报数(1,2,3..依次报),数到m的士兵会被杀死出列,之后的士兵再从1开始报数。直到最后剩下一士兵。求这个士兵的编号。
方法一:数组
第一次做这个题的时候,第一反应就是用数组来做。创建一个boolean数组,用true表示没出列,false表示出列,定义一个计数器,遍历数组,当加到与m相等时,就将true变为false,计数器变为零,重新计数。
public class Test {
private static Integer compute(Integer n, Integer m) {
Boolean[] peopleFlags = new Boolean[n];
for (int i = 0; i < n; i++) {
peopleFlags[i] = true;
}
int peopleLeft = n; //剩下的人数
int count = 0; //计数器,每过一个人加一,加到m时归零
int index = 0; //开始下标
while (peopleLeft > 1) {
if (peopleFlags[index]) {
count++;
if (count == m) {
count = 0;
peopleFlags[index] = false;
peopleLeft--;
}
}
index++;
//当当前人等于总人数时,则又从第一人开始计数
if (index == n) {
index = 0;
}
}
for (int j = 0; j < n; j++) {
if (peopleFlags[j]) {
return j + 1;
}
}
return null;
}
public static void main(String[] args) {
int n = 52;
int m = 3;
Integer winner = compute(n, m);
System.out.println(winner);
}
}
方法二:链表
先实现一个循环链表,在把编号添加到链表里面,也需要一个计数器,初始值为1,遍历链表,当计数器的值等于m是,计数器变为1,删除当下节点。依次直到循环结束。
public class Test2 {
static class Node{
int date;
Node next;
public Node(int date){
this.date = date;
}
}
public static int solve(int n,int m){
if(m == 1 || n<2){
return n;
}
Node head = createLinkedList(n);
int count = 1;
Node cur = head;
Node pre = null;
while(true){
//当剩下两个节点时,不能用pre.next = cur.next,会死循环
if(cur.next == pre && m == 3){
pre = cur.next;
break;
}
if(count == m){
count = 1;
pre.next = cur.next;
cur = pre.next;
}else{
count++;
pre = cur;
cur = cur.next;
}
}
return pre.date;
}
public static Node createLinkedList(int n){
Node head = new Node(1);
Node next = head;
for(int i = 2;i<=n;i++){
Node tmp = new Node(i);
next.next = tmp;
next = next.next;
}
//头尾串联
next.next = head;
return head;
}
public static void main(String[] args) {
int a = solve(52,3);
System.out.println(a);
}
}
方法三:递归
每次在让一个士兵出列后,对剩下的重新编号。
删除前的编号和删除后编号对比
m-2 n-2
m-1 n-1
m 已删除
m+1 1
m+2 2
这样我们就可以得到删除前的编号与删除后的编号的关系:删除前编号 = (删除后编号+m-1)%n+1,为什么不是删除前编号 = (删除后编号+m)%n,因为编号是从1开始的,拖过删除后的编号+m = n,那么删除前的结果就为0,不符合。
public class Test3 {
public static int f(int n,int m){
if(n == 1){
return 1;
}
return (f(n-1,m) + m-1) % n +1;
}
public static void main(String[] args) {
System.out.println(f(52,3));
}
}
1198

被折叠的 条评论
为什么被折叠?



