Problem
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:
- Start at the
1st
friend. - Count the next
k
friends in the clockwise direction including the friend you started at. The counting wraps around the circle and may count some friends more than once. - The last friend you counted leaves the circle and loses the game.
- If there is still more than one friend in the circle, go back to step
2
starting from the friend immediately clockwise of the friend who just lost and repeat. - Else, the last friend in the circle wins the game.
Given the number of friends, n
, and an integer k
, return the winner of the game.
Josephus circle
This is also called Josephus circle:
N people have decided to elect a leader by arranging themselves in a circle and eliminating every Mth person around the circle, closing ranks as each person drops out. Find which person will be the last one remaining (with rank 1).
Examples
Example 1:
Input: n = 5, k = 2
Output: 3
Explanation: Here are the steps of the game:
1) Start at friend 1.
2) Count 2 friends clockwise, which are friends 1 and 2.
3) Friend 2 leaves the circle. Next start is friend 3.
4) Count 2 friends clockwise, which are friends 3 and 4.
5) Friend 4 leaves the circle. Next start is friend 5.
6) Count 2 friends clockwise, which are friends 5 and 1.
7) Friend 1 leaves the circle. Next start is friend 3.
8) Count 2 friends clockwise, which are friends 3 and 5.
9) Friend 5 leaves the circle. Only friend 3 is left, so they are the winner.
Example 2:
Input: n = 6, k = 5
Output: 1
Explanation: The friends leave in this order: 5, 4, 6, 2, 3. The winner is friend 1.
Solution
Method 1 - Brute Force
We can do following:
- Use a list to represent the friends sitting in a circle.
- Use a loop to simulate the process of eliminating every kth friend until only one friend remains.
- Calculate the index of the next friend to be eliminated using
(currIdx + k - 1) % friends.size()
. This ensures the count wraps around the circle. - Remove the friend at
currIdx
from the list.
- Calculate the index of the next friend to be eliminated using
Code
Java
public class Solution {
public int findTheWinner(int n, int k) {
List<Integer> friends = new ArrayList<>();
for (int i = 1; i <= n; i++) {
friends.add(i);
}
int currIdx = 0; // Start from the 1st friend
while (friends.size() > 1) {
// Compute the index of the friend to be removed
currIdx = (currIdx + k - 1) % friends.size();
// Remove that friend
friends.remove(currIdx);
}
// The last remaining friend is the winner
return friends.get(0);
}
}
Complexity
- ⏰ Time complexity:
O(n^2)
, wheren
is number of friends.- Adding the friends take
O(n)
time - Now, we remove
n - 1
friends from list, and removing 1 friend from list by value takesO(n)
. So, it should beO((n-1)*n)
⇨O(n^2)
.
- Adding the friends take
- 🧺 Space complexity:
O(n)
for storing n friends
Method 2 - Using Queue
Instead of using list, we use the queue to store the friends.
- Use a queue to represent the friends sitting in a circle.
- Now, to eliminate
n - 1
friends, we can run the loop till queue size is 1, OR run loopn - 1
- Now, each time we start from first friend, and count k. We send
k - 1
friends to the end of queue - But kth friend will eliminated from list
- Now, each time we start from first friend, and count k. We send
[!NOTE] Note For the interview purpose, this method may not be required, until it is asked as a mathematical problem.
Here is the video explanation:
Dry Run
Initialization
1 => 2 => 3 => 4 => 5
First Round
Move 1 to the end:
2 => 3 => 4 => 5 => 1
Remove the node at the current step, which is k:
3 => 4 => 5 => 1
Second Round
Move 3 to the end:
4 => 5 => 1 => 3
Remove 4:
5 => 1 => 3
Third Round
Move 5 to the end:
1 => 3 => 5
Remove 1:
3 => 5
Fourth Round
Move 3 to the end:
5 => 3
Remove 5:
3
Code
Java
class Solution {
public int findTheWinner(int n, int k) {
Queue<Integer> friends = new LinkedList<>();
for (int i = 1; i <= n; i++) {
friends.add(i);
}
for (int i = 1; i <= (n - 1); i++) {
for (int j = 1; j < k; j++) {
friends.add(friends.poll()); // simulate counting
}
friends.poll(); // Eliminate the kth friend
}
// Return the last friend remaining
return friends.poll();
}
}
Complexity
- ⏰ Time complexity:
O(n*k)
- Adding the friends take
O(n)
time - Then, we run elimination round n - 1 times, for k friends which takes
O(n*k)
- Adding the friends take
- 🧺 Space complexity:
O(n)
Method 3 - Mathematics and recursion
Lets convert it to recursive function. Let’s assume we have f(n,k)
which will gives us one remaining after nth
turn in a group of nth people if we count k person at each turn. Lets assume 0-based index.
Then, the base case is n = 1 - If there is only one person left, the winner’s index is 0 (since 0-based index).
f(1, k) = 0
For generic n
:
f(n,k) = (f(n-1, k)+k) % n
Our answer will be, as this is 1-based output.
g(n, k) = f(n, k) + 1;
Dry Run
We start with g(5, 2) = f(5, 2) + 1
.
f(5,2)
calls f(4,2)
calls f(3,2)
calls f(2,2)
calls f(1,2)
.
Now, f(1,2)
returns 0.
We can unwind the recursion stack now:
f(2,2) = (f(1,2) + k) % n = (0 + 2) % 2 = 0
f(3,2) = (f(2,2) + k) % n = (0 + 2) % 3 = 2
f(4,2) = (f(3,2) + k) % n = (2 + 2) % 4 = 0
f(5,2) = (f(4,2) + k) % n = (0 + 2) % 5 = 2
Now, we adjust for 1-based indexing:
g(5,2) = f(5,2) + 1 = 2 + 1 = 3
Code
Java
class Solution {
public int findTheWinner(int n, int k) {
return findTheWinner0Based(n, k)+1;
}
public int findTheWinner0Based(int n, int k) {
if(n == 1) {
return 0;
} else {
return (findTheWinner0Based(n - 1, k) + k) % n;
}
}
}
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(n)
for using recursion stack
Method 4 - Mathematics and iterative
Code
Java
class Solution {
public int findTheWinner(int n, int k) {
int idx = 0;
for(int i=1; i<=n; i++) {
idx = (idx + k) % i;
}
return idx + 1;
}
}
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(1)