持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。
因此每天刷刷LeetCode非常有必要
在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode
一、题目描述
共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。
游戏遵循如下规则:
- 从第 1 名小伙伴所在位置 开始 。
- 沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。
- 你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。
- 如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。
- 否则,圈子中最后一名小伙伴赢得游戏。
- 给你参与游戏的小伙伴总数 n ,和一个整数 k ,返回游戏的获胜者。
二、思路分析
不删减数组的元素,就会导致下标比较难处理。
并且需要注意:需要while循环判断当前是否已经被标记过,标记过的下标就不能再次被计算。
创建一个标记数组vis,用于记录当前的小伙伴是否被淘汰。
如果被淘汰了,就记录为1;否则记为0
最终的结果,就是vis数组中为0的小伙伴
三、代码实现
/**
* @param {number} n
* @param {number} k
* @return {number}
*/
var findTheWinner = function(n, k) {
// 使用数组和visited标记
let vis = new Array(n).fill(0), num = 1,arr = new Array(n).fill(0).map((value, index) => index + 1);
// 初始化开始下标`start` 和 终止下标`end`
let start = 0, end = start + k - 1;
// 循环次数,淘汰掉`n - 1`个小伙伴时,就可以得到答案
while(num < n) {
// 如果终止下标,已经被淘汰了,那么就需要循环查找
while(vis[end] == 1) {
end++;
end %= n;
}
// 将终止下标淘汰
vis[end] = 1;
// 开始下标的位置,为上一个淘汰的下标的下一个
start = (end + 1) % n;
// 如果,当前的开始下标已经被淘汰,循环查找没有被淘汰的开始下标
while(vis[start] == 1) {
start++;
start %= n;
}
// 根据当前的开始下标 查找 有效的终止下标
let nn = 1, t = start;
// 开始下标 和 终止下标的 差距为`k`
while(nn < k) {
t = t % n;
if(vis[t] == 0) {
//可以算作一个
t = (t + 1) % n;
}else {
// 不能算作一个
while(vis[t] != 0) {
t = (t + 1) % n;
}
t = (t + 1) % n;
}
nn++;
}
end = t % n;
num++;
}
// 查找`vis`数组中值为`0`的下标,并将其在`arr`数组中进行映射
let idx = -Infinity;
vis.forEach((value, index) => {
if(value == 0){
idx = index;
}
});
return arr[idx];
};
四、总结
以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~