【我也想刷穿 LeetCode啊】1823. 找出游戏的获胜者

68 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情

现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。

因此每天刷刷LeetCode非常有必要

在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode

一、题目描述

共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。

游戏遵循如下规则:

  1. 从第 1 名小伙伴所在位置 开始 。
  2. 沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。
  3. 你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。
  4. 如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。
  5. 否则,圈子中最后一名小伙伴赢得游戏。
  6. 给你参与游戏的小伙伴总数 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];
};

四、总结

以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~