题目为击鼓传花游戏,在这个游戏中,孩子们围成一个圆圈,把花尽快地传递给旁边的人。某一时刻传花停止,这个时候花在谁手里,谁就退出圆圈结束游戏。重复这个过程,直到只剩一个孩子(胜者)。
// 需要思考passGame如何写
var names = ["John", "Jack", "Camila", "Ingrid", "Carl"];
var endName = passGame(names, 8); // 数到 8 的人淘汰
console.log("最终留下:" + endName); // 'john'
思考
先尝试自己思考,用我愚蠢的脑瓜想出来两个解决方案
方案一
用变量now代表当前的列表索引位置,max代表数组长度,interval代表数到几淘汰,counter代表计数器每次到8清零。循环使用splice删除元素。最后得到胜利者。
方案二
用变量now代表索引位置,使用模计算,8%5余3,删除第三个,然后记录新的索引位置,8%4余0,删除最后一个...最后得到胜利者。
但以上两种方案,对于now的控制很麻烦,虽然都可以完成题目,但是变量变化以后非常容易出错。并不是好的解决方案。
学习
寻找答案后,这题考的是队列的使用。
队列:优先队列+循环队列(击鼓传花算法)
感谢大佬的分享
解决
学习了队列的概念
队列是遵循FIFO(First In First Out,先进先出,也称为先来先服务)原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾。
该问题的解决思路也就很简单了,计数的同时,把队首的元素移动到队尾,计数器到了指定的数,就删除队首,循环这个操作,直到队列长度为1即可。这样就不会出现上面now定位不准确的问题。
// 定义队列类
function Queue() {
this.list = [];
// add-在队尾添加
this.add = function (item) {
this.list.push(item);
};
// del-从队首删除,并返回删除的值
this.del = function () {
return this.list.shift();
};
// size-返回队列长度
this.size = function () {
return this.list.length;
};
}
// 游戏逻辑
function passGame(nameList, interval) {
// 声明实例和幸存者
let q = new Queue() , eliminated = '';
// 给实例中的队列赋值
q.list = nameList;
// 当队列长度大于1时执行
while (q.size() > 1) {
// 开始计数,每次把队首元素移动到队尾
for (let j = 0; j < interval; j++) {
q.add(q.del());
}
// 到达指定数量,删除当前元素。
eliminated = q.del()
console.log(eliminated + "被淘汰");
}
// 最后返回幸存者
return q.list[0];
}
var names = ["Yimiao", "Jack", "Camila", "Ingrid", "Carl"];
var endName = passGame(names, 8); // 数到 8 的人淘汰
console.log("最终留下:" + endName); // 'Yimiao'
var names = ["John", "Jack", "Camila", "Ingrid", "Carl"];
var endName = passGame(names, 8); // 数到 8 的人淘汰
console.log("最终留下:" + endName); // 'john'
// Camila被淘汰
// Jack被淘汰
// Carl被淘汰
// Ingrid被淘汰
// 最终留下:Yimiao