leetcode
leetcode 2301 ~ 2350
找出转圈游戏输家

找出转圈游戏输家

难度:

标签:

题目描述

There are n friends that are playing a game. The friends are sitting in a circle and are numbered from 1 to n in clockwise order. More formally, moving clockwise from the ith friend brings you to the (i+1)th friend for 1 <= i < n, and moving clockwise from the nth friend brings you to the 1st friend.

The rules of the game are as follows:

1st friend receives the ball.

  • After that, 1st friend passes it to the friend who is k steps away from them in the clockwise direction.
  • After that, the friend who receives the ball should pass it to the friend who is 2 * k steps away from them in the clockwise direction.
  • After that, the friend who receives the ball should pass it to the friend who is 3 * k steps away from them in the clockwise direction, and so on and so forth.

In other words, on the ith turn, the friend holding the ball should pass it to the friend who is i * k steps away from them in the clockwise direction.

The game is finished when some friend receives the ball for the second time.

The losers of the game are friends who did not receive the ball in the entire game.

Given the number of friends, n, and an integer k, return the array answer, which contains the losers of the game in the ascending order.

 

Example 1:

Input: n = 5, k = 2
Output: [4,5]
Explanation: The game goes as follows:
1) Start at 1st friend and pass the ball to the friend who is 2 steps away from them - 3rd friend.
2) 3rd friend passes the ball to the friend who is 4 steps away from them - 2nd friend.
3) 2nd friend passes the ball to the friend who is 6 steps away from them  - 3rd friend.
4) The game ends as 3rd friend receives the ball for the second time.

Example 2:

Input: n = 4, k = 4
Output: [2,3,4]
Explanation: The game goes as follows:
1) Start at the 1st friend and pass the ball to the friend who is 4 steps away from them - 1st friend.
2) The game ends as 1st friend receives the ball for the second time.

 

Constraints:

  • 1 <= k <= n <= 50

代码结果

运行时间: 28 ms, 内存: 16.7 MB


/*
 * Problem Description:
 * n friends are playing a game sitting in a circle, numbered from 1 to n in clockwise order. 
 * The 1st friend starts with the ball and passes it to the friend k steps away in the clockwise direction.
 * The game continues where the friend who receives the ball passes it to the friend 2*k steps away, then 3*k, and so on.
 * The game ends when a friend receives the ball for the second time.
 * The goal is to return the list of friends who never received the ball.
 */

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class FriendsGameStream {
    public static List<Integer> findLosers(int n, int k) {
        boolean[] received = new boolean[n]; // Tracks who received the ball
        int currentIndex = 0; // Starting from the 1st friend (index 0)
        int passCount = 1; // Initial pass count
        while (true) {
            if (received[currentIndex]) {
                break; // Game ends when a friend receives the ball for the second time
            }
            received[currentIndex] = true;
            currentIndex = (currentIndex + passCount * k) % n;
            passCount++;
        }
        return IntStream.range(0, n)
                .filter(i -> !received[i])
                .mapToObj(i -> i + 1) // Converting to 1-based index
                .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        System.out.println(findLosers(5, 2)); // Output: [4, 5]
        System.out.println(findLosers(4, 4)); // Output: [2, 3, 4]
    }
}

解释

方法:

此题解采用模拟的方式来跟踪球的传递过程。首先,初始化一个布尔数组 `friend` 来标记每个朋友是否接过球。数组的索引表示朋友的编号(从0开始,即编号1的朋友是 `friend[0]`)。游戏从第1个朋友开始,因此 `friend[0]` 初始化为 `True`。随后,使用变量 `temp` 来记录当前持球者的位置,并用变量 `i` 来记录传球的轮次。游戏继续进行,直到一个朋友第二次接到球,此时游戏结束。最后,遍历 `friend` 数组,将未接过球的朋友编号(加1后)添加到结果列表 `result` 中。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
如何确保模拟的过程中每个朋友的编号正确地映射到数组`friend`的索引上?
在本题的模拟中,朋友的编号被直接映射到数组 `friend` 的索引上,其中朋友编号从1开始,但数组索引从0开始。因此,当我们引用 `friend[0]` 时,实际上是指的第1个朋友,`friend[1]` 是第2个朋友,依此类推。这种映射通过在数组操作时将朋友编号减去1来实现,从而确保每个朋友的编号正确地对应到数组索引上。
🦆
在计算新的接球者位置时,`temp += i * k`步骤中的`i * k`增长可能非常快,是否有可能导致性能问题或者整数溢出?
虽然`i * k`的结果随着游戏轮次的增加而快速增长,但在每次计算后立即使用`temp %= n`将其模上n(朋友总数),保证`temp`始终在合理范围内(0到n-1)。这样做有效避免了整数溢出的问题,并且由于`temp`的值始终受到n的限制,所以不会导致性能问题。
🦆
题解中提到当`friend[temp]`为真并且不是第1轮时游戏结束,这是否意味着游戏总是在第二次某人接球时立即停止?如果是这样,如何处理尚未参与接球的朋友?
是的,根据题解逻辑,游戏将在某个朋友第二次接到球时立即结束。在游戏结束后,将会检查`friend`数组,列出所有值为假的索引,即那些未曾接到球的朋友。这些朋友的编号(索引+1)将被添加到结果列表`result`中,从而确保所有未参与接球的朋友都被正确处理。
🦆
题解中假设第一次接球的朋友不会立即结束游戏。请问这是基于什么规则或假设?
这是基于游戏规则的假设和设计。题解中假设游戏始于第1个朋友接球,并且在第1轮中,`friend[0]` 被设置为 `True`。因为游戏需要在某人第二次接球时才结束,所以第1轮接球不会导致游戏结束。这个设定是为了确保游戏至少完整进行一轮,让每个朋友都有可能接到球。

相关问题