题目如下:
现有1000人,一字排开,开始报数,第一轮报偶数的出局,报基数的人留下,留下的人重新报数,第二轮报基数的出局,报偶数的留下,留下的人重新报数,第三轮同第一轮一样报偶数的出局,报基数的人留下,留下的人重新报数,第四轮同第二轮一样报基数的出局,报偶数的留下。依次轮流,基数次报数留报基数的人,偶数次报数留报偶数的人。最后留下一个人,请问这个人在第一次报数时报的是多少?
两种解法,解法2是朋友想出
解法1:
// 链表
ArrayList list = new ArrayList(1000);
for (int i = 1; i < 1001; i++) {
list.add(i);
}
int qs = 1;
while (true) {
// 判断list大小是否为1 如果为1则循环结束
if (list.size() == 1) {
System.out.println("循环了" + qs + "圈最后剩下的数字" + list.get(0));
return;
}
// 判断是否奇数圈,如果奇数圈移除偶数位的数字,否则移除奇数位的数字
for (int k = 0; k < list.size(); k++) {
if (k % 2 != 0 && qs % 2 == 1) {
list.set(k, "0");
} else if (k % 2 == 0 && qs % 2 == 0) {
list.set(k, "0");
}
}
for (int i = 0; i < list.size(); i++) {
if ("0".equals(list.get(i))) {
list.remove(i);
}
}
qs++;// 圈数
}
解法2:
boolean delFalg = true;//圈数状态,如果是奇书圈则为真
int count = 1000;//人数
int[] mans = new int[1000];//定义一个长度为1000的数组,只用下标
while (count > 1) {
int l = 0;
//循环减人
for (int i = 0; i < mans.length; i++) {
if (mans[i] == 1)//如果当前数组下标已经被赋予值,说明之前已经被减掉,跳过
continue;
l++;
//如果符合奇数圈偶数位或者偶数圈奇数位将数据组对应下标赋值
if (delFalg && l % 2 == 0 || !delFalg && l % 2 != 0) {
mans[i] = 1;
count--;
}
}
delFalg = !delFalg;//每次循环反转状态,用来标志奇偶圈数
}
//找出下标位对应值为0的数组下标 它的所在位数就是对应第一次叫的数字
for (int i = 0; i < mans.length; i++) {
if (mans[i] == 0) {
System.out.println("剩下的人的第一次报数为:" + (++i));
break;
}
}