Find the Winner of the Circular Game (LeetCode 1823)
n friends sit around a circle, labeled 1 through n going clockwise, so stepping clockwise past friend n wraps you straight back to friend 1.
Play unfolds like this:
- Everyone begins with friend
1as the current spot. - From there, tick off
kfriends moving clockwise, counting the current friend as the first tick -- looping around the circle again ifkis larger than however many friends remain. - Whichever friend the
k-th tick lands on is eliminated and steps out of the circle. - As long as two or more friends remain, the next round starts its count from the friend standing immediately clockwise of the one who just left.
- Once only one friend is left, that friend is declared the winner.
Given n and k, work out which friend wins.
Worked Examples
n = 5, k = 23n = 6, k = 51⚖️Formal Constraints & Bounds
1 <= k <= n <= 500
Core Insight
Simulating circular array deletion takes O(n * k) or O(n^2) time. The subproblem recurrence f(n, k) = (f(n - 1, k) + k) % n computes the answer iteratively in O(N) time with O(1) extra space.
Real-World Scenario & Production Applications
Counting-out games, where players stand in a circle and every k-th player drops out until one is left, like a playground rhyme that picks who is "it".
Subproblems & Recurrence Decomposition3 Phases
With exactly 1 person in the circle, position 0 (0-indexed) trivially wins -- there's no one else to eliminate.
if n == 1:
return 0Step-by-Step Execution Trace Table
| Iteration i (Circle Size) | Subproblem State f(i, k) | Shift (+ k) | Modulo (% i) | Winner (0-indexed) |
|---|---|---|---|---|
| 1 | Base case (single person) | 0 | 0 % 1 = 0 | 0 |
| 2 | (0 + 2) % 2 | 2 | 2 % 2 = 0 | 0 |
| 3 | (0 + 2) % 3 | 2 | 2 % 3 = 2 | 2 |
| 4 | (2 + 2) % 4 | 4 | 4 % 4 = 0 | 0 |
| 5 | (0 + 2) % 5 | 2 | 2 % 5 = 2 | 2 (1-indexed -> 3) |
The Math, Step by Step
1. The winner as a seat number from 0
Number the seats from 0 instead of from 1: friend sits at seat . Write for the seat of the winner in a game with friends that starts counting at seat 0. The answer to the problem is .
A game with one friend needs no round, so .
2. What the first round does
In a game of friends, the count starts at seat 0 and ticks off friends. The -th tick lands on seat , and that friend leaves. Here is the remainder after dividing by , which wraps the count around the circle. The next round starts at the seat right after it, seat .
Now friends are left, and the next count starts at seat . This is a new game of friends. Give its seats new numbers, starting with 0 at seat :
| New seat in the game of | Old seat in the game of |
|---|---|
| 0 | |
| 1 | |
The new numbering has seats 0 to . A new seat would be old seat , the friend who left, so it is not part of the smaller game.
3. The recurrence
The smaller game follows exactly the same rules, so its winner sits at new seat . The table turns that into an old seat:
Starting from , the code applies this rule for . It never simulates the circle. This is the Josephus recurrence.
4. Why the seats count from 0
The mod of part 3 only works with seats numbered from 0. The remainder is always between 0 and , which are exactly the seat numbers. With seats numbered from 1, a remainder of 0 would name a seat that does not exist. So the code works with from 0 and adds 1 only at the end, in return winner + 1.
may be larger than the number of friends left, for example with 2 friends. The mod handles this, because counting past the last seat wraps to the first.
5. Example 1 by hand
n = 5, k = 2.
size | winner before | winner + k | winner = (winner + k) % size |
|---|---|---|---|
| 2 | 0 | 2 | |
| 3 | 0 | 2 | |
| 4 | 2 | 4 | |
| 5 | 0 | 2 |
, so the code returns , the expected output. A direct simulation removes friends 2, 4, 1 and 5, and friend 3 is left, which agrees.
6. Example 2 by hand
n = 6, k = 5.
size | winner before | winner + k | winner = (winner + k) % size |
|---|---|---|---|
| 2 | 0 | 5 | |
| 3 | 1 | 6 | |
| 4 | 0 | 5 | |
| 5 | 1 | 6 | |
| 6 | 1 | 6 |
, so the code returns , the expected output. A direct simulation removes friends 5, 4, 6, 2 and 3, and friend 1 is left.
7. From the math to the code
| Math | In findTheWinner |
|---|---|
winner = 0 | |
for size in range(2, n + 1): | |
winner = (winner + k) % size | |
| friend number | return winner + 1 |
The loop runs times with one addition and one remainder each, so the code takes time and space.
| 1 | winner = 0 |
| 2 | for size in range(2, n + 1): |
| 3 | winner = (winner + k) % size |
| 4 | return winner + 1 |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
Simulating the entire circle of friends being eliminated one by one feels like the obvious approach — but this solution never simulates a single elimination. It builds the answer backward, from the smallest possible circle up.
🔄 The Analogy: Rewind, Then Fast-Forward One Person at a Time
Start from the trivial case: with just 1 friend in the circle, that friend obviously wins — position 0. Now imagine you already know the winning position for a circle of size - 1 friends. What happens when you add one more friend to make a circle of size? The entire elimination pattern is identical to before — it's just been rotated by k seats, and wrapped around a slightly bigger circle. So the new winner's seat is simply the old winner's seat, shifted by k, wrapped around using the new, larger circle size.
You never touch a real elimination — you just replay "shift by k, wrap around" one circle-size at a time, growing the circle from 1 person up to n.
🔑 The Key Idea in the Code
Each loop iteration answers "if I already know the winner for a circle of size - 1 friends, what's the winner for a circle of size friends?" — a single O(1) rotation, repeated n - 1 times, instead of an O(N·K) simulation of the whole game.
1-indexed to 0-indexed conversion off-by-one: The mathematical recurrence operates on 0-indexed positions. Forgetting to add at the final return violates 1-indexed output requirements.
Simulating with list deletion taking time: Simulating circle elimination with
list.pop(index)takes time due to array element shifts. The bottom-up iterative DP formula computes the survivor in time and space.Base case :
winnerstarts at 0, the seat of the only friend counted from 0; the function still returnswinner + 1 = 1.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
"n friends sit around a circle", "the k-th tick ... is eliminated and steps out of the circle", "the next round starts its count from the friend standing immediately clockwise" and "once only one friend is left, that friend is declared the winner": every k-th one leaves a circle and only the last one is asked for. That is the Josephus Problem: solve the smaller circle, then shift its answer.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
Invariant: winner is the 0-indexed seat of the winner for size friends. Going from size - 1 to size friends shifts that seat by k: winner = (winner + k) % size.
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
The card's trap: start from
winner = 0and add 1 only in the finalreturn.kcan be larger than the circle (up ton):(winner + k) % sizealready counts whole laps, so no special case is needed.
The 60-Second Interview Pitch
Say this out loud before you type a single line
I'd use the Josephus recurrence. Once the first friend leaves, what's left is the same game with one friend fewer, only started k seats later. So if
winneris the 0-indexed winner forsize - 1friends, the winner forsizefriends is(winner + k) % size. That's correct because removing the k-th friend and restarting from the next seat is exactly the smaller circle shifted by k seats, and% sizewraps the shift around the bigger circle. I start withwinner = 0for one friend and loopsizefrom 2 up to n. The trap is the index base: the recurrence counts seats from 0 but the friends are numbered from 1, so I add 1 only in the final return. That'sO(N)time andO(1)space.
Complexity & Mathematical Proof
O(N)
Look at the execution steps: Bottom-up Josephus recurrence: f(1) = 0, f(i) = (f(i-1) + k) % i for i from 2 to N. Single linear for-loop with N - 1 arithmetic updates.
O(1) Auxiliary
Look at memory allocations: Call stack uses O(1) Iterative. Single scalar integer register storing winner index in O(1) space.
Derivation Progression
f(1) = 0
With 1 person, winner is at 0-based index 0.
f(i) = (f(i-1) + k) (mod i)
Remaps winner index when subproblem size expands from i-1 to i.
N-1 arithmetic steps = O(N)
Computes exact winner in single linear loop.
Variable Definitions
Total number of friends in the circular game
Step counting offset for eliminations
Memory Architecture & Bounds
O(1) Iterative
O(1) Single integer register
O(1) 1-based winner integer
Boundary Best / Worst Cases
Recurrence Tree Topology
Senior SWE Deconstruction & Hardware Caveats
Structural triggers: "clock-wise circular order", "eliminate every k-th friend", "last friend remaining". Direct simulation via linked list or array pop costs or time. A Senior SWE immediately recognizes the historic Josephus Problem, solvable in time and space using bottom-up dynamic programming via cyclic coordinate shifting.
: at most constant-time updates, with no list of friends and no node allocation.
With fixed-width integers, winner + k is below , which only overflows a 32-bit int once passes .
Core Algorithmic State Invariants
- Only the Winner Is Cheap
The recurrence tracks one seat, the winner's, so it never knows who left in which round. If a problem asks for the whole elimination order, you have to simulate the removals instead.
- k = 2 Has a Closed Form
For k = 2, write n = 2^m + L with 0 <= L < 2^m: the winner (numbered from 1) is 2L + 1. For n = 5 = 4 + 1 that is 3, which the loop also returns.
- Loop, Not Recursion
The same rule written top-down, f(size) = (f(size - 1) + k) % size, recurses n levels deep. The loop from size = 2 up to n gives the same answer with no call stack.
Find the Winner of the Circular Game (LeetCode 1823)
n friends sit around a circle, labeled 1 through n going clockwise, so stepping clockwise past friend n wraps you straight back to friend 1.
Play unfolds like this:
- Everyone begins with friend
1as the current spot. - From there, tick off
kfriends moving clockwise, counting the current friend as the first tick -- looping around the circle again ifkis larger than however many friends remain. - Whichever friend the
k-th tick lands on is eliminated and steps out of the circle. - As long as two or more friends remain, the next round starts its count from the friend standing immediately clockwise of the one who just left.
- Once only one friend is left, that friend is declared the winner.
Given n and k, work out which friend wins.
Worked Examples
n = 5, k = 23n = 6, k = 51⚖️Formal Constraints & Bounds
1 <= k <= n <= 500
Core Insight
Simulating circular array deletion takes O(n * k) or O(n^2) time. The subproblem recurrence f(n, k) = (f(n - 1, k) + k) % n computes the answer iteratively in O(N) time with O(1) extra space.
Real-World Scenario & Production Applications
Counting-out games, where players stand in a circle and every k-th player drops out until one is left, like a playground rhyme that picks who is "it".
Subproblems & Recurrence Decomposition3 Phases
With exactly 1 person in the circle, position 0 (0-indexed) trivially wins -- there's no one else to eliminate.
if n == 1:
return 0Step-by-Step Execution Trace Table
| Iteration i (Circle Size) | Subproblem State f(i, k) | Shift (+ k) | Modulo (% i) | Winner (0-indexed) |
|---|---|---|---|---|
| 1 | Base case (single person) | 0 | 0 % 1 = 0 | 0 |
| 2 | (0 + 2) % 2 | 2 | 2 % 2 = 0 | 0 |
| 3 | (0 + 2) % 3 | 2 | 2 % 3 = 2 | 2 |
| 4 | (2 + 2) % 4 | 4 | 4 % 4 = 0 | 0 |
| 5 | (0 + 2) % 5 | 2 | 2 % 5 = 2 | 2 (1-indexed -> 3) |
The Math, Step by Step
1. The winner as a seat number from 0
Number the seats from 0 instead of from 1: friend sits at seat . Write for the seat of the winner in a game with friends that starts counting at seat 0. The answer to the problem is .
A game with one friend needs no round, so .
2. What the first round does
In a game of friends, the count starts at seat 0 and ticks off friends. The -th tick lands on seat , and that friend leaves. Here is the remainder after dividing by , which wraps the count around the circle. The next round starts at the seat right after it, seat .
Now friends are left, and the next count starts at seat . This is a new game of friends. Give its seats new numbers, starting with 0 at seat :
| New seat in the game of | Old seat in the game of |
|---|---|
| 0 | |
| 1 | |
The new numbering has seats 0 to . A new seat would be old seat , the friend who left, so it is not part of the smaller game.
3. The recurrence
The smaller game follows exactly the same rules, so its winner sits at new seat . The table turns that into an old seat:
Starting from , the code applies this rule for . It never simulates the circle. This is the Josephus recurrence.
4. Why the seats count from 0
The mod of part 3 only works with seats numbered from 0. The remainder is always between 0 and , which are exactly the seat numbers. With seats numbered from 1, a remainder of 0 would name a seat that does not exist. So the code works with from 0 and adds 1 only at the end, in return winner + 1.
may be larger than the number of friends left, for example with 2 friends. The mod handles this, because counting past the last seat wraps to the first.
5. Example 1 by hand
n = 5, k = 2.
size | winner before | winner + k | winner = (winner + k) % size |
|---|---|---|---|
| 2 | 0 | 2 | |
| 3 | 0 | 2 | |
| 4 | 2 | 4 | |
| 5 | 0 | 2 |
, so the code returns , the expected output. A direct simulation removes friends 2, 4, 1 and 5, and friend 3 is left, which agrees.
6. Example 2 by hand
n = 6, k = 5.
size | winner before | winner + k | winner = (winner + k) % size |
|---|---|---|---|
| 2 | 0 | 5 | |
| 3 | 1 | 6 | |
| 4 | 0 | 5 | |
| 5 | 1 | 6 | |
| 6 | 1 | 6 |
, so the code returns , the expected output. A direct simulation removes friends 5, 4, 6, 2 and 3, and friend 1 is left.
7. From the math to the code
| Math | In findTheWinner |
|---|---|
winner = 0 | |
for size in range(2, n + 1): | |
winner = (winner + k) % size | |
| friend number | return winner + 1 |
The loop runs times with one addition and one remainder each, so the code takes time and space.
| 1 | winner = 0 |
| 2 | for size in range(2, n + 1): |
| 3 | winner = (winner + k) % size |
| 4 | return winner + 1 |
Conceptual Narrative
🧭 Conceptual Foundation & Pattern Intuition
Simulating the entire circle of friends being eliminated one by one feels like the obvious approach — but this solution never simulates a single elimination. It builds the answer backward, from the smallest possible circle up.
🔄 The Analogy: Rewind, Then Fast-Forward One Person at a Time
Start from the trivial case: with just 1 friend in the circle, that friend obviously wins — position 0. Now imagine you already know the winning position for a circle of size - 1 friends. What happens when you add one more friend to make a circle of size? The entire elimination pattern is identical to before — it's just been rotated by k seats, and wrapped around a slightly bigger circle. So the new winner's seat is simply the old winner's seat, shifted by k, wrapped around using the new, larger circle size.
You never touch a real elimination — you just replay "shift by k, wrap around" one circle-size at a time, growing the circle from 1 person up to n.
🔑 The Key Idea in the Code
Each loop iteration answers "if I already know the winner for a circle of size - 1 friends, what's the winner for a circle of size friends?" — a single O(1) rotation, repeated n - 1 times, instead of an O(N·K) simulation of the whole game.
1-indexed to 0-indexed conversion off-by-one: The mathematical recurrence operates on 0-indexed positions. Forgetting to add at the final return violates 1-indexed output requirements.
Simulating with list deletion taking time: Simulating circle elimination with
list.pop(index)takes time due to array element shifts. The bottom-up iterative DP formula computes the survivor in time and space.Base case :
winnerstarts at 0, the seat of the only friend counted from 0; the function still returnswinner + 1 = 1.
4-Phase Thought Process Model
Pattern Recognition Signals
The 10-second spot
"n friends sit around a circle", "the k-th tick ... is eliminated and steps out of the circle", "the next round starts its count from the friend standing immediately clockwise" and "once only one friend is left, that friend is declared the winner": every k-th one leaves a circle and only the last one is asked for. That is the Josephus Problem: solve the smaller circle, then shift its answer.
Formulating the Predicate & Invariants
Turning intuition into a boolean rule
Invariant: winner is the 0-indexed seat of the winner for size friends. Going from size - 1 to size friends shifts that seat by k: winner = (winner + k) % size.
Silent Failure Traps & Edge Cases
Where confident candidates still lose points
The card's trap: start from
winner = 0and add 1 only in the finalreturn.kcan be larger than the circle (up ton):(winner + k) % sizealready counts whole laps, so no special case is needed.
The 60-Second Interview Pitch
Say this out loud before you type a single line
I'd use the Josephus recurrence. Once the first friend leaves, what's left is the same game with one friend fewer, only started k seats later. So if
winneris the 0-indexed winner forsize - 1friends, the winner forsizefriends is(winner + k) % size. That's correct because removing the k-th friend and restarting from the next seat is exactly the smaller circle shifted by k seats, and% sizewraps the shift around the bigger circle. I start withwinner = 0for one friend and loopsizefrom 2 up to n. The trap is the index base: the recurrence counts seats from 0 but the friends are numbered from 1, so I add 1 only in the final return. That'sO(N)time andO(1)space.
Complexity & Mathematical Proof
O(N)
Look at the execution steps: Bottom-up Josephus recurrence: f(1) = 0, f(i) = (f(i-1) + k) % i for i from 2 to N. Single linear for-loop with N - 1 arithmetic updates.
O(1) Auxiliary
Look at memory allocations: Call stack uses O(1) Iterative. Single scalar integer register storing winner index in O(1) space.
Derivation Progression
f(1) = 0
With 1 person, winner is at 0-based index 0.
f(i) = (f(i-1) + k) (mod i)
Remaps winner index when subproblem size expands from i-1 to i.
N-1 arithmetic steps = O(N)
Computes exact winner in single linear loop.
Variable Definitions
Total number of friends in the circular game
Step counting offset for eliminations
Memory Architecture & Bounds
O(1) Iterative
O(1) Single integer register
O(1) 1-based winner integer
Boundary Best / Worst Cases
Recurrence Tree Topology
Senior SWE Deconstruction & Hardware Caveats
Structural triggers: "clock-wise circular order", "eliminate every k-th friend", "last friend remaining". Direct simulation via linked list or array pop costs or time. A Senior SWE immediately recognizes the historic Josephus Problem, solvable in time and space using bottom-up dynamic programming via cyclic coordinate shifting.
: at most constant-time updates, with no list of friends and no node allocation.
With fixed-width integers, winner + k is below , which only overflows a 32-bit int once passes .
Core Algorithmic State Invariants
- Only the Winner Is Cheap
The recurrence tracks one seat, the winner's, so it never knows who left in which round. If a problem asks for the whole elimination order, you have to simulate the removals instead.
- k = 2 Has a Closed Form
For k = 2, write n = 2^m + L with 0 <= L < 2^m: the winner (numbered from 1) is 2L + 1. For n = 5 = 4 + 1 that is 3, which the loop also returns.
- Loop, Not Recursion
The same rule written top-down, f(size) = (f(size - 1) + k) % size, recurses n levels deep. The loop from size = 2 up to n gives the same answer with no call stack.