整体逻辑:
先标记数到3的人
截取末尾不够数到3的人,他们将是下次报数的开始
过滤标记的人,也就是把报3的删除
将截取的人拼到数组的最前面 ,记得数组末尾要删除他们
拼接好的数组继续执行上述操作,直到数组长度为3,也就是递归到出口
递归出口:当2人或者3人报数时,结果是固定的,都是2号位留下
代码如下:
let arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']
function fn(arr) {
//当数组最后长度为3时,结果就可以直接输出了
if (arr.length <= 3) {
return arr[1]
}
//遍历数组,将报到3的人做标记,让它为0
for (let i = 0; i < arr.length; i++) {
//数组下标是从0开始的,但是报数是从1开始的,所以这里要下标加1,再取余
if ((i + 1) % 3 == 0) {
arr[i] = 0
}
}
//筛选所有不为0的人为新数组
let newarr = arr.filter((v) => v != 0)
// 截取原数组报到最后一个0后,还剩几个人 arr.slice(-(arr.length % 3))
//新数组 删除我们截取的数组(或者说截取我们需要的部分)
newarr = newarr.slice(0, newarr.length - (arr.length % 3))
//将截取的数组 合并 到新数组的前边
//合并后的结果作为参数,进行递归
return fn(arr.slice(-(arr.length % 3)).concat(newarr))
}
//输出最后剩余的谁
console.log(fn(arr));
//输出剩余的原来的几号
console.log(arr.indexOf(fn(arr)) + 1);