#1823MediumSimulation
Find the Winner of the Circular Game
Start dumb: act it out
The problem is a procedure, so the honest first solution is to perform it:
put 1..n in a list, keep an index, and each round step forward k
positions over whoever is left, delete that friend, and continue from the
next one. Repeat until a single friend remains. That’s exactly the code the
player runs — clear, correct, and O(n·k) because each of the n−1
deletions walks up to k steps (and a list removeAt shifts elements).
Find the bottleneck
Walking k positions and shifting a list on every elimination is a lot of
work for a question that only wants one number: the survivor’s seat. The
whole circle is being maintained just to read off a single final index.
The optimal shape
Two ways to land the answer:
- Simulate (shown here): a list, an index,
(start + k − 1) % size, delete, repeat. Easiest to see; every elimination is a real, visible move. - Recurrence: fold
f(n) = (f(n-1) + k) mod nfromf(1) = 0up ton, then returnf(n) + 1to convert the 0-based seat to a 1-based friend number.
Both give the same winner; the recurrence just refuses to move any friends
around. In the player, the count starts at the start pointer and lands on
out — the friend who leaves. Eliminated friends stay in place on dashed
tiles so you can watch the count skip over them.
Watch it think
Run the default 5 | 2 (winner 3), then 6 | 5 (winner 1 — a larger step
that wraps the circle), and 1 | 1, where the game is over before it starts.
Re-traces as you type — friends n, a pipe, then the counting step k — e.g. "5 | 2" (winner 3); try "6 | 5" or the trivial "1 | 1". Capped at 32 characters so the tiles stay readable.
Step 1 of 6: The 5 friends stand in a fixed circle, and the count always begins at friend 1 — only friends still present are ever counted. Variables: n = 5, k = 2, remaining = 5.
Data
Code
1fun findTheWinner(n: Int, k: Int): Int {2 val circle = (1..n).toMutableList()3 var start = 04 while (circle.size > 1) {5 val idx = (start + k - 1) % circle.size6 circle.removeAt(idx)7 start = idx8 }9 return circle[0]10}
State
- n
- 5
- k
- 2
- remaining
- 5
Why this step
The 5 friends stand in a fixed circle, and the count always begins at friend 1 — only friends still present are ever counted.
1 / 6
The same pattern also solves
Recognize the window, and these fall to the same skeleton.
- Josephus Problem (the classic)
This IS the Josephus problem; the O(n) recurrence f(n) = (f(n-1) + k) mod n replaces the O(n·k) simulation shown here.
- Elimination Game (LC 390)
Same eliminate-every-other idea on a line that reverses each pass — solved by tracking only the head, not the whole circle.
- Design Circular Queue (LC 622)
The data structure underneath — wrapping an index modulo the size is exactly the circle's arithmetic.
- Last Stone Weight (LC 1046)
Another "repeatedly remove until one remains" simulation, but the choice of what to remove is driven by a heap.