题目是这样(没什么注释):
数三退一问题是:
有一圈(500人)孩子,手拉手围成一个圈,从第一个孩子开始数1,第二个孩子数2,第三个孩子数3,这时候数3的孩子退出,从下一个孩子开始数1,一直循环,直到最后剩下一个孩子,问这个孩子的位置?
加1主要是因为编号是从 1 开始的,而不是从 0 开始的,因为求出的结果是数组中的下标
第一种解法(for循环):
public void result(){
int sum = 0;
for (int i = 2; i <= 500; i++) {
sum = (sum + 3) % i;
}
System.out.println(sum + 1); //输出剩下的那个人的位置
}
// 递归方式
public int f(int n, int m) {
if(n == 1) return n;
return (f(n - 1, m) + m - 1) % n + 1;
}
第二种解法(使用集合):
public static void yuesefu(int totalNum, int countNum, int startNO) {
// 初始化人数
List<Integer> start = new ArrayList<Integer>();
for (int i = 1; i <= totalNum; i++) {
start.add(i);
}
// 从下标为K开始计数
int k = startNO - 1;
while (start.size() > 0) {
System.out.println(start);
// 第m人的索引位置
k = (k + countNum) % (start.size()) - 1;
// 判断是否到队尾 到队尾时候k=-1
if (k < 0) {
System.out.println(start.get(start.size() - 1));
start.remove(start.size() - 1);
k = 0;
} else {
System.out.println(start.get(k));
start.remove(k);
}
}
}
public static void main(String[] args){
yuesefu(500, 3, 1);
}
第三种解法(使用数组):
public void result2(){
boolean[] kids;
kids = new boolean[500]; //声明一个500人的数组
for (int i = 0; i < kids.length; i++) {
kids[i] = true;
}
int leftNum = kids.length;
int countNum = 0;
int index = 0;
while (leftNum > 1) {
if (kids[index]) {
countNum++;
}
if (countNum == 3) {
kids[index] = false;
countNum = 0;
leftNum--;
}
index++;
if (index == 500) {
index = 0;
}
}
for (int i = 0; i < kids.length; i++) {
if (kids[i]) {
System.out.println(i+1);
}
}
}
第四种解法(使用面向对象方法):
public static void main(String[] args) {
// 数3退1;每数到3就退出一个,面向对象的方法
// 面向对象,考虑问题中出现的名词:小孩类,圈类
KidCircle kc = new KidCircle(500);
Kid k = kc.first;// 先取出kc的第一个孩子
int countNum = 0;// 用来数数,数到3退出
while (kc.count > 1) {
countNum++;
if (countNum == 3) {
countNum = 0;
kc.delete(k);
}
k = k.right;// 因为是圆环,所以,每次取k孩子的右孩子
}
System.out.println("剩余的小孩的编号为:" + (kc.first.id+1));
}
}
// 小孩类
class Kid {
int id;// 小孩原始编号
/*
* 每个小孩都有左小孩和右相邻小孩
*/
Kid left;
Kid right;
}
// 圈类
class KidCircle {
int count = 0;// 小孩编号
Kid first;// 圈中第一个小孩
Kid last;// 圈中最后一个小孩
/*
* 写完成员变量以后首先完成其构造方法
*/
public KidCircle(int n)// 构造方法一般用来初始化
{
// 构造n个小孩的圈
for (int i = 0; i < n; i++) {
add();
}
}
// 向圈中添加小孩
void add() {
Kid k = new Kid();
k.id = count;
if (count <= 0) // 当前圈中没有小孩
{
first = k;
last = k;
k.left = k;
k.right = k;
} else // 当前圈中有小孩情况
{
last.right = k;
k.left = last;
k.right = first;
first.left = k;
last = k;
}
count++;
}
// 向圈中删除小孩
void delete(Kid k) {
if (count <= 0)
return;
else if (count == 1) // 这个地方为什么
{
first = last = null;
} else {
k.left.right = k.right;
k.right.left = k.left;
if (k == first) // 当要删除小孩为第一个小孩时
first = k.right;
else if (k == last) {
last = k.left;
}
}
count--;
}
代码运行结果:436