Find The First Player to win K Games in a Row
MedPrompt
A competition consists of n players numbered from 0 to n - 1.
You are given an integer array skills of size n and a positive integer k, where skills[i] is the skill level of player i. All integers in skills are unique.
All players are standing in a queue in order from player 0 to player n - 1.
The competition process is as follows:
- The first two players in the queue play a game, and the player with the higher skill level wins.
- After the game, the winner stays at the beginning of the queue, and the loser goes to the end of it.
The winner of the competition is the first player who wins k games in a row.
Return the initial index of the winning player.
Example 1:
Input: skills = [4,2,6,3,9], k = 2
Output: 2
Explanation:
Initially, the queue of players is [0,1,2,3,4]. The following process happens:
- Players 0 and 1 play a game, since the skill of player 0 is higher than that of player 1, player 0 wins. The resulting queue is
[0,2,3,4,1]. - Players 0 and 2 play a game, since the skill of player 2 is higher than that of player 0, player 2 wins. The resulting queue is
[2,3,4,1,0]. - Players 2 and 3 play a game, since the skill of player 2 is higher than that of player 3, player 2 wins. The resulting queue is
[2,4,1,0,3].
Player 2 won k = 2 games in a row, so the winner is player 2.
Example 2:
Input: skills = [2,5,4], k = 3
Output: 1
Explanation:
Initially, the queue of players is [0,1,2]. The following process happens:
- Players 0 and 1 play a game, since the skill of player 1 is higher than that of player 0, player 1 wins. The resulting queue is
[1,2,0]. - Players 1 and 2 play a game, since the skill of player 1 is higher than that of player 2, player 1 wins. The resulting queue is
[1,0,2]. - Players 1 and 0 play a game, since the skill of player 1 is higher than that of player 0, player 1 wins. The resulting queue is
[1,2,0].
Player 1 won k = 3 games in a row, so the winner is player 1.
Constraints:
n == skills.length2 <= n <= 1051 <= k <= 1091 <= skills[i] <= 106- All integers in
skillsare unique.
Approaches
3 approaches with complexity analysis and trade-offs.
This approach directly simulates the game process described in the problem statement using an ArrayList to represent the queue of players. While it's a straightforward translation of the rules, its performance is hampered by the choice of data structure. Operations like removing from the front of an ArrayList are costly, making this solution impractical for the given constraints.
Algorithm
- Create an
ArrayListto store the queue of player indices, from0ton-1. - Initialize a
currentWinnerIdxandwinStreakvariable to track the winning player and their streak. - Enter a loop that continues as long as no player has won
kgames. - Inside the loop, get the first two players from the list,
p1andp2. - Compare their skills to find the
winnerandloser. - Update the
winStreak. If thewinneris the same ascurrentWinnerIdx, increment the streak. Otherwise, updatecurrentWinnerIdxand reset the streak to 1. - If
winStreakequalsk, returncurrentWinnerIdx. - Modify the list to reflect the game's outcome: remove the two players from the front and add the
winnerto the front and theloserto the back. This step is inefficient with anArrayList.
Walkthrough
In this method, we initialize an ArrayList with player indices from 0 to n-1. We then enter a simulation loop. In each iteration, we identify the first two players in the list, compare their skills, and determine the winner and loser. We update the list by removing the two contestants and re-inserting them according to the rules: the winner at the front, the loser at the back. We also maintain a count of consecutive wins for the current champion. The simulation stops and returns the champion's index as soon as their win streak reaches k. The main drawback is that list.remove(0) and list.add(0, element) are O(N) operations, and since the simulation can run up to O(N) games, the total time complexity becomes quadratic.
import java.util.ArrayList;import java.util.List; class Solution { public int findWinningPlayer(int[] skills, int k) { int n = skills.length; List<Integer> queue = new ArrayList<>(); for (int i = 0; i < n; i++) { queue.add(i); } // Optimization for very large k to pass some cases if (k >= n) { int maxIdx = 0; for (int i = 1; i < n; i++) { if (skills[i] > skills[maxIdx]) { maxIdx = i; } } return maxIdx; } int currentWinnerIdx = -1; int winStreak = 0; while (true) { int p1_idx = queue.get(0); int p2_idx = queue.get(1); int winnerIdx, loserIdx; if (skills[p1_idx] > skills[p2_idx]) { winnerIdx = p1_idx; loserIdx = p2_idx; } else { winnerIdx = p2_idx; loserIdx = p1_idx; } if (winnerIdx == currentWinnerIdx) { winStreak++; } else { currentWinnerIdx = winnerIdx; winStreak = 1; } if (winStreak == k) { return currentWinnerIdx; } // Inefficient queue update using ArrayList queue.remove(0); queue.remove(0); queue.add(0, winnerIdx); queue.add(loserIdx); } }}Complexity
Time
O(N^2). The number of games simulated is at most `O(N)`. Each game involves list modifications that take `O(N)` time.
Space
O(N) to store the player indices in the `ArrayList`.
Trade-offs
Pros
Conceptually simple and easy to map from the problem description.
Cons
Extremely inefficient due to the use of an
ArrayListfor queue operations.Removing elements from the front of an
ArrayListtakesO(N)time, leading to a poor overall time complexity.Will likely result in a 'Time Limit Exceeded' error on platforms with larger test cases.
This approach significantly improves upon the previous one by choosing a more suitable data structure. By using a Deque (like ArrayDeque in Java), all queue operations—getting players from the front, adding the winner to the front, and adding the loser to the back—can be performed in constant time. The simulation logic remains the same, but the efficiency is greatly enhanced.
Algorithm
- Use a
Deque(Double-Ended Queue), such asArrayDeque, which is optimized for adding and removing elements from both ends. - Populate the
Dequewith player indices from0ton-1. - Keep track of the
winnerIdxand theirwinStreak. - Loop until a player's
winStreakreachesk. - In each iteration, use
pollFirst()to get the two players at the front of the queue. - Compare their skills to determine the
winnerandloser. - Use
addFirst(winner)to place the winner at the front andaddLast(loser)to place the loser at the back. These areO(1)operations. - Update the
winStreakandwinnerIdxaccordingly. - Return
winnerIdxwhenwinStreakequalsk.
Walkthrough
The core idea is still to simulate the tournament game by game. However, we replace the ArrayList with a Deque. This is crucial because a Deque provides O(1) time complexity for adding or removing elements from either the head or the tail.
The simulation proceeds as follows: we take the first two players, they compete, the winner is put back at the front, and the loser at the end. We track the current winner and their streak. The key insight for the time complexity is that the total number of games that need to be simulated is bounded by O(N). This is because after a certain number of games (at most 2N-2), the player with the highest skill will have reached the front and defeated every other player, establishing a permanent winning streak. Therefore, the simulation will always terminate in a linear number of steps.
import java.util.ArrayDeque;import java.util.Deque; class Solution { public int findWinningPlayer(int[] skills, int k) { int n = skills.length; Deque<Integer> queue = new ArrayDeque<>(); for (int i = 0; i < n; i++) { queue.add(i); } if (k >= n) { int maxIdx = 0; for (int i = 1; i < n; i++) { if (skills[i] > skills[maxIdx]) { maxIdx = i; } } return maxIdx; } int winnerIdx = queue.peekFirst(); int winStreak = 0; while (winStreak < k) { int p1 = queue.pollFirst(); int p2 = queue.pollFirst(); if (skills[p1] > skills[p2]) { queue.addFirst(p1); queue.addLast(p2); if (winnerIdx == p1) { winStreak++; } else { winnerIdx = p1; winStreak = 1; } } else { queue.addFirst(p2); queue.addLast(p1); winnerIdx = p2; winStreak = 1; } } return winnerIdx; }}Complexity
Time
O(N). The number of games is bounded by `O(N)`, and each game is processed in `O(1)` time.
Space
O(N) to store the `Deque` of player indices.
Trade-offs
Pros
Efficient
O(N)time complexity.Correctly models the game dynamics.
Handles all constraints effectively.
Cons
Requires extra space proportional to the number of players.
This is the most optimal solution, achieving linear time complexity with constant extra space. It avoids creating an explicit queue data structure. Instead, it recognizes that the game is a series of challenges where a reigning winner defends their position against subsequent players in the initial lineup. We only need to track the current winner's index and their win streak as we iterate through the challengers once.
Algorithm
- Initialize
current_winner_idx = 0andconsecutive_wins = 0. - Iterate through the players from index
i = 1ton-1, treating each as a challenger. - In each iteration, compare the skill of the
current_winner_idxwith the challengeri. - If the current winner wins (
skills[current_winner_idx] > skills[i]): Incrementconsecutive_wins. - If the challenger wins (
skills[i] > skills[current_winner_idx]): Updatecurrent_winner_idxtoiand resetconsecutive_winsto1. - After each game, check if
consecutive_wins == k. If it is, returncurrent_winner_idx. - If the loop finishes, it means the
current_winner_idxholds the index of the strongest player overall. This player will never lose again, so they are the guaranteed winner. Returncurrent_winner_idx.
Walkthrough
We can simulate the process without an actual queue. The player at the front of the queue is the current winner. They will play against every subsequent player until they are defeated. If they are defeated, the challenger becomes the new winner, and the simulation continues from there.
We can implement this with a single pass. We start by assuming player 0 is the winner. We then iterate from player 1 to n-1. In each step, we pit the current_winner against the challenger i. If the winner prevails, their win streak increases. If the challenger wins, they become the new winner, and their streak starts at 1. If at any point a player's streak reaches k, they are the answer.
A crucial observation is what happens if the loop completes without anyone reaching k wins. The player who is the current_winner at the end of the loop must have a higher skill than all players who came after them. This means they are the player with the highest skill in the entire array. They will never be defeated again and will eventually reach k wins. Thus, they are the final answer.
class Solution { public int findWinningPlayer(int[] skills, int k) { int n = skills.length; int current_winner_idx = 0; int consecutive_wins = 0; for (int i = 1; i < n; i++) { if (skills[current_winner_idx] > skills[i]) { consecutive_wins++; } else { current_winner_idx = i; consecutive_wins = 1; } if (consecutive_wins == k) { return current_winner_idx; } } // If the loop completes, the current winner is the strongest player overall. // They will keep winning, so they are the answer for any remaining k. return current_winner_idx; }}Complexity
Time
O(N), as we perform a single pass through the skills array.
Space
O(1), as we only use a few variables to store the state.
Trade-offs
Pros
Optimal
O(N)time complexity.Optimal
O(1)space complexity.Elegant and concise implementation.
Cons
The logic might be slightly less direct to derive compared to a literal queue simulation.
Solutions
Solution
class Solution {public int findWinningPlayer(int[] skills, int k) { int n = skills.length; k = Math.min(k, n - 1); int i = 0, cnt = 0; for (int j = 1; j < n; ++j) { if (skills[i] < skills[j]) { i = j; cnt = 1; } else { ++cnt; } if (cnt == k) { break; } } return i; }}class Solution {public: int findWinningPlayer(vector<int> &skills, int k) { int n = skills.size(); k = min(k, n - 1); int i = 0, cnt = 0; for (int j = 1; j < n; ++j) { if (skills[i] < skills[j]) { i = j; cnt = 1; } else { ++cnt; } if (cnt == k) { break; } } return i; }};class Solution: def findWinningPlayer(self, skills: List[int], k: int) -> int: n = len(skills) k = min(k, n - 1) i = cnt = 0 for j in range(1, n): if skills[i] < skills[j]: i = j cnt = 1 else: cnt += 1 if cnt == k: break return iVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.