Facebook Pixel

3175. Find The First Player to win K Games in a Row

MediumArraySimulation
Leetcode Link

Problem Description

You have n players numbered from 0 to n - 1 standing in a queue in order. Each player has a unique skill level given in the array skills, where skills[i] represents the skill level of player i.

The competition works as follows:

  • The first two players in the queue compete against each other
  • The player with the higher skill level wins the game
  • The winner stays at the front of the queue, while the loser moves to the back of the queue
  • This process continues until one player wins k games in a row

Your task is to find the initial index of the player who first achieves k consecutive wins.

For example, if skills = [4, 2, 6, 3, 9] and k = 2:

  • Players 0 (skill 4) and 1 (skill 2) compete → Player 0 wins, Player 1 goes to the back
  • Players 0 (skill 4) and 2 (skill 6) compete → Player 2 wins, Player 0 goes to the back, Player 2's win count = 1
  • Players 2 (skill 6) and 3 (skill 3) compete → Player 2 wins, Player 3 goes to the back, Player 2's win count = 2
  • Player 2 has won 2 consecutive games, so the answer is 2

The key insight is that we don't need to simulate the entire queue process. We can track the current winner and their consecutive win count while iterating through the array once. If a player defeats all other n-1 players, they are guaranteed to be the winner regardless of k's value, which is why the solution uses k = min(k, n - 1).

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Let's think about what happens during the competition. Initially, players 0 and 1 compete. The winner stays at position 0, and we then compare this winner with player 2. Then with player 3, and so on.

The key observation is that we're essentially finding which player can beat k consecutive opponents as we traverse through the array. The winner at any point stays at the front and faces the next player in line.

Here's the crucial insight: if we've gone through all n-1 other players (comparing them with our current champion), then our current champion has beaten everyone at least once. After this point, the champion will keep winning forever since they have the highest skill level. This means that if k >= n-1, we just need to find the player with the maximum skill level.

That's why we can simplify the problem by setting k = min(k, n-1). We don't need to simulate beyond n-1 comparisons.

Now, instead of actually simulating the queue operations (which would be expensive), we can just iterate through the array once:

  • Keep track of the current "champion" (initially player 0)
  • Count their consecutive wins
  • When we encounter a stronger player, they become the new champion with a win count of 1
  • When the current champion beats another player, increment their win count
  • Stop when someone reaches k wins

This linear scan approach works because the order of comparisons is exactly what would happen if we were actually moving losers to the back of the queue - each player gets compared with the current champion in their original order.

Solution Approach

The solution implements a single-pass algorithm that simulates the competition without actually manipulating a queue.

Key Steps:

  1. Optimization of k: First, we set k = min(k, n - 1). This is because after comparing with all n-1 other players, the current champion must be the strongest player overall and will win all future games.

  2. Initialize tracking variables:

    • i = 0: Index of the current champion (starts with player 0)
    • cnt = 0: Count of consecutive wins for the current champion
  3. Linear traversal: We iterate through players 1 to n-1 using index j:

    • Compare skills[i] (current champion) with skills[j] (challenger)
    • If skills[i] < skills[j]:
      • Player j wins and becomes the new champion
      • Update i = j (new champion index)
      • Reset cnt = 1 (new champion has 1 win)
    • If skills[i] >= skills[j]:
      • Current champion wins
      • Increment cnt += 1
  4. Early termination: If at any point cnt == k, we've found our winner and can break out of the loop.

  5. Return the result: The index i represents the initial position of the winning player.

Why this works:

  • The order of comparisons in our iteration matches exactly what would happen in the actual queue simulation
  • Player at index i faces players at indices i+1, i+2, ..., n-1 in sequence
  • If player i loses to player j, then j becomes the new champion and faces the remaining players
  • This avoids the O(n) space and time complexity of actual queue operations

Time Complexity: O(n) - single pass through the array Space Complexity: O(1) - only using a few variables to track state

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example with skills = [3, 7, 2, 5, 1] and k = 3.

Step 1: Optimization

  • n = 5, so k = min(3, 5-1) = min(3, 4) = 3

Step 2: Initialize

  • i = 0 (player 0 with skill 3 is our initial champion)
  • cnt = 0 (no wins yet)

Step 3: Simulate competitions

Round 1 (j = 1):

  • Compare player 0 (skill 3) vs player 1 (skill 7)
  • 3 < 7, so player 1 wins
  • Update: i = 1, cnt = 1
  • Current champion: player 1 with 1 win

Round 2 (j = 2):

  • Compare player 1 (skill 7) vs player 2 (skill 2)
  • 7 > 2, so player 1 wins
  • Update: cnt = 2
  • Current champion: player 1 with 2 wins

Round 3 (j = 3):

  • Compare player 1 (skill 7) vs player 3 (skill 5)
  • 7 > 5, so player 1 wins
  • Update: cnt = 3
  • Current champion: player 1 with 3 wins

Step 4: Check termination

  • cnt == k (3 == 3), so we found our winner!
  • Break the loop

Step 5: Return result

  • Return i = 1

Player at index 1 (with skill level 7) is the first to achieve 3 consecutive wins. Note how we didn't need to actually move players to the back of a queue - we just compared the current champion with each subsequent player in order, which gives us the same result as the actual queue simulation would.

Solution Implementation

1from typing import List
2
3
4class Solution:
5    def findWinningPlayer(self, skills: List[int], k: int) -> int:
6        """
7        Find the index of the player who wins k consecutive games.
8      
9        In this game, players compete based on their skill values.
10        The player with higher skill wins and stays to face the next challenger.
11      
12        Args:
13            skills: List of integers representing each player's skill level
14            k: Number of consecutive wins needed
15          
16        Returns:
17            Index of the winning player
18        """
19        n = len(skills)
20      
21        # Optimization: if k >= n-1, the strongest player will eventually win
22        # since they would face all other players
23        k = min(k, n - 1)
24      
25        # Track the current champion's index and their consecutive win count
26        current_winner_index = 0
27        consecutive_wins = 0
28      
29        # Iterate through all challengers starting from index 1
30        for challenger_index in range(1, n):
31            if skills[current_winner_index] < skills[challenger_index]:
32                # Challenger wins, becomes the new champion
33                current_winner_index = challenger_index
34                consecutive_wins = 1
35            else:
36                # Current champion wins, increment their win count
37                consecutive_wins += 1
38          
39            # Check if current champion has reached k consecutive wins
40            if consecutive_wins == k:
41                break
42      
43        return current_winner_index
44
1class Solution {
2    public int findWinningPlayer(int[] skills, int k) {
3        int arrayLength = skills.length;
4      
5        // Optimization: if k >= n-1, the winner must have won against all other players
6        // So we cap k at n-1 since that's the maximum meaningful consecutive wins
7        int targetWins = Math.min(k, arrayLength - 1);
8      
9        // Track the current champion (player who is currently winning)
10        int currentChampionIndex = 0;
11      
12        // Track consecutive wins of the current champion
13        int consecutiveWins = 0;
14      
15        // Iterate through all other players to challenge the champion
16        for (int challengerIndex = 1; challengerIndex < arrayLength; ++challengerIndex) {
17          
18            // Check if challenger defeats the current champion
19            if (skills[currentChampionIndex] < skills[challengerIndex]) {
20                // Challenger wins and becomes the new champion
21                currentChampionIndex = challengerIndex;
22                consecutiveWins = 1;  // Reset win count for new champion
23            } else {
24                // Current champion wins, increment their win count
25                ++consecutiveWins;
26            }
27          
28            // Check if current champion has reached the target number of wins
29            if (consecutiveWins == targetWins) {
30                break;  // Found the winner, exit early
31            }
32        }
33      
34        // Return the index of the winning player
35        return currentChampionIndex;
36    }
37}
38
1class Solution {
2public:
3    int findWinningPlayer(vector<int>& skills, int k) {
4        int n = skills.size();
5      
6        // Optimization: if k >= n-1, the winner must have won against all others
7        // So we cap k at n-1 to avoid unnecessary iterations
8        k = min(k, n - 1);
9      
10        // Track the current champion (player at front of queue)
11        int currentChampion = 0;
12      
13        // Count consecutive wins for the current champion
14        int consecutiveWins = 0;
15      
16        // Simulate matches starting from position 1
17        for (int challenger = 1; challenger < n; ++challenger) {
18            if (skills[currentChampion] < skills[challenger]) {
19                // Current champion loses, challenger becomes new champion
20                currentChampion = challenger;
21                consecutiveWins = 1;  // New champion has 1 win
22            } else {
23                // Current champion wins, increment win count
24                ++consecutiveWins;
25            }
26          
27            // Check if current champion has reached k consecutive wins
28            if (consecutiveWins == k) {
29                break;
30            }
31        }
32      
33        // Return the index of the winning player
34        return currentChampion;
35    }
36};
37
1/**
2 * Finds the index of the winning player in a game where players compete based on skills.
3 * Players compete in order, and a player wins if they win k consecutive rounds.
4 * 
5 * @param skills - Array of skill values for each player
6 * @param k - Number of consecutive wins needed to be declared the winner
7 * @returns The index of the winning player
8 */
9function findWinningPlayer(skills: number[], k: number): number {
10    const playerCount: number = skills.length;
11  
12    // Optimize k: if k >= playerCount - 1, the strongest player will definitely win
13    const winsNeeded: number = Math.min(k, playerCount - 1);
14  
15    // Track current champion index and their consecutive win count
16    let currentChampionIndex: number = 0;
17    let consecutiveWins: number = 0;
18  
19    // Simulate the competition starting from the second player
20    for (let challengerIndex: number = 1; challengerIndex < playerCount; challengerIndex++) {
21        if (skills[currentChampionIndex] < skills[challengerIndex]) {
22            // Challenger wins: becomes the new champion
23            currentChampionIndex = challengerIndex;
24            consecutiveWins = 1;
25        } else {
26            // Current champion wins: increment their win count
27            consecutiveWins++;
28        }
29      
30        // Check if current champion has reached required wins
31        if (consecutiveWins === winsNeeded) {
32            break;
33        }
34    }
35  
36    return currentChampionIndex;
37}
38

Time and Space Complexity

Time Complexity: O(n) where n is the length of the skills array.

The algorithm iterates through the skills array once with a single for loop from index 1 to n-1. In each iteration, it performs constant time operations (comparisons and variable updates). Even though there's a break statement that could terminate the loop early when cnt == k, in the worst case scenario, the loop will run through all n-1 iterations (when the strongest player is at the beginning or when no player wins k consecutive games before reaching the end).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space. It maintains a few integer variables (n, k, i, cnt, j) regardless of the input size. The modification of k with min(k, n-1) is also done in-place without creating any additional data structures. The input array is not modified and no auxiliary data structures are created.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Not Optimizing k Value

A common mistake is forgetting to cap k at n-1. Without this optimization, the algorithm might continue unnecessary iterations even after a player has defeated everyone else.

Incorrect approach:

# Without optimization
for challenger_index in range(1, n):
    # ... competition logic ...
    if consecutive_wins == k:  # k could be very large
        break

Why it's problematic: If k = 1000000 and n = 5, after a player beats all 4 others, they're guaranteed to win all future matches. The loop would continue unnecessarily.

Solution: Always use k = min(k, n - 1) at the beginning.

2. Incorrect Win Count Initialization

Some might initialize the consecutive wins counter incorrectly when a new champion emerges.

Incorrect approach:

if skills[current_winner_index] < skills[challenger_index]:
    current_winner_index = challenger_index
    consecutive_wins = 0  # Wrong! Should be 1

Why it's problematic: When a challenger defeats the current champion, they've just won their first game. Setting consecutive_wins = 0 would require an extra unnecessary iteration to reach k wins.

Solution: Always set consecutive_wins = 1 when a new champion emerges, as they've just won their first game.

3. Off-by-One Error in Loop Range

Starting the loop from index 0 instead of 1, or misunderstanding the initial state.

Incorrect approach:

current_winner_index = 0
consecutive_wins = 1  # Wrong! Player 0 hasn't won yet
for challenger_index in range(0, n):  # Wrong! Starts from 0
    # ...

Why it's problematic:

  • Player at index 0 starts as the first competitor but hasn't won any games yet
  • Starting the loop from 0 would make player 0 compete against themselves

Solution: Initialize consecutive_wins = 0 and start the loop from index 1.

4. Mishandling the Case When k = 1

Special edge case where any single win should immediately return the winner.

Potential issue:

# If not handled properly, might miss immediate wins
if k == 1:
    # First comparison determines the winner
    return 0 if skills[0] >= skills[1] else 1

Why it's problematic: While this specific handling works, it adds unnecessary complexity. The general algorithm already handles k = 1 correctly.

Solution: Trust the general algorithm to handle all cases uniformly, including k = 1.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which of the following array represent a max heap?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More