跳转至

2682. 找出转圈游戏输家

题目描述

n 个朋友在玩游戏。这些朋友坐成一个圈,按 顺时针方向1n 编号。准确的说,从第 i 个朋友的位置开始顺时针移动 1 步会到达第 (i + 1) 个朋友的位置(1 <= i < n),而从第 n 个朋友的位置开始顺时针移动 1 步会回到第 1 个朋友的位置。

游戏规则如下:

1 个朋友接球。

  • 接着,第 1 个朋友将球传给距离他顺时针方向 k 步的朋友。
  • 然后,接球的朋友应该把球传给距离他顺时针方向 2 * k 步的朋友。
  • 接着,接球的朋友应该把球传给距离他顺时针方向 3 * k 步的朋友,以此类推。

换句话说,在第 i 轮中持有球的那位朋友需要将球传递给距离他顺时针方向 i * k 步的朋友。

当某个朋友第 2 次接到球时,游戏结束。

在整场游戏中没有接到过球的朋友是 输家

给你参与游戏的朋友数量 n 和一个整数 k ,请按升序排列返回包含所有输家编号的数组 answer 作为答案。

 

示例 1:

输入:n = 5, k = 2
输出:[4,5]
解释:以下为游戏进行情况:
1)第 1 个朋友接球,第 1 个朋友将球传给距离他顺时针方向 2 步的玩家 —— 第 3 个朋友。
2)第 3 个朋友将球传给距离他顺时针方向 4 步的玩家 —— 第 2 个朋友。
3)第 2 个朋友将球传给距离他顺时针方向 6 步的玩家 —— 第 3 个朋友。
4)第 3 个朋友接到两次球,游戏结束。

示例 2:

输入:n = 4, k = 4
输出:[2,3,4]
解释:以下为游戏进行情况:
1)第 1 个朋友接球,第 1 个朋友将球传给距离他顺时针方向 4 步的玩家 —— 第 1 个朋友。
2)第 1 个朋友接到两次球,游戏结束。

 

提示:

  • 1 <= k <= n <= 50

解法

方法一:模拟

我们用一个数组 vis 记录每个朋友是否接到过球,初始时所有朋友都没有接到过球。然后我们按照题目描述的规则模拟游戏的过程,直到某个朋友第二次接到球为止。

在模拟过程中,我们用两个变量 $i$ 和 $p$ 分别表示当前持球的朋友编号和当前传球的步长。初始时 $i=0,p=1$,表示第一个朋友接到球。每次传球时,我们将 $i$ 更新为 $(i+p \times k) \bmod n$,表示下一个接球的朋友编号,然后将 $p$ 更新为 $p+1$,表示下一次传球的步长。当某个朋友第二次接到球时,游戏结束。

最后我们遍历数组 vis,将没有接到过球的朋友编号加入答案数组中即可。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是朋友的数量。

1
2
3
4
5
6
7
8
9
class Solution:
    def circularGameLosers(self, n: int, k: int) -> List[int]:
        vis = [False] * n
        i, p = 0, 1
        while not vis[i]:
            vis[i] = True
            i = (i + p * k) % n
            p += 1
        return [i + 1 for i in range(n) if not vis[i]]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
    public int[] circularGameLosers(int n, int k) {
        boolean[] vis = new boolean[n];
        int cnt = 0;
        for (int i = 0, p = 1; !vis[i]; ++p) {
            vis[i] = true;
            ++cnt;
            i = (i + p * k) % n;
        }
        int[] ans = new int[n - cnt];
        for (int i = 0, j = 0; i < n; ++i) {
            if (!vis[i]) {
                ans[j++] = i + 1;
            }
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
class Solution {
public:
    vector<int> circularGameLosers(int n, int k) {
        bool vis[n];
        memset(vis, false, sizeof(vis));
        for (int i = 0, p = 1; !vis[i]; ++p) {
            vis[i] = true;
            i = (i + p * k) % n;
        }
        vector<int> ans;
        for (int i = 0; i < n; ++i) {
            if (!vis[i]) {
                ans.push_back(i + 1);
            }
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func circularGameLosers(n int, k int) (ans []int) {
    vis := make([]bool, n)
    for i, p := 0, 1; !vis[i]; p++ {
        vis[i] = true
        i = (i + p*k) % n
    }
    for i, x := range vis {
        if !x {
            ans = append(ans, i+1)
        }
    }
    return
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function circularGameLosers(n: number, k: number): number[] {
    const vis = new Array(n).fill(false);
    const ans: number[] = [];
    for (let i = 0, p = 1; !vis[i]; p++) {
        vis[i] = true;
        i = (i + p * k) % n;
    }
    for (let i = 0; i < vis.length; i++) {
        if (!vis[i]) {
            ans.push(i + 1);
        }
    }
    return ans;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
impl Solution {
    pub fn circular_game_losers(n: i32, k: i32) -> Vec<i32> {
        let mut vis: Vec<bool> = vec![false; n as usize];

        let mut i = 0;
        let mut p = 1;
        while !vis[i] {
            vis[i] = true;
            i = (i + p * (k as usize)) % (n as usize);
            p += 1;
        }

        let mut ans = Vec::new();
        for i in 0..vis.len() {
            if !vis[i] {
                ans.push((i + 1) as i32);
            }
        }

        ans
    }
}

评论