Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Calculating Josephus Permutations efficiently in JavaScript
This problem takes its name from arguably the most important event in the life of the ancient historian Josephus. According to his tale, he and his 40 soldiers were trapped in a cave by the Romans during a siege.
Refusing to surrender to the enemy, they instead opted for mass suicide, with a twist ? they formed a circle and proceeded to kill one man every three, until one last man was left (and that it was supposed to kill himself to end the act).
Josephus and another man were the last two and, as we now know every detail of the story, you may have correctly guessed that they didn't exactly follow through the original idea.
We are required to write a JavaScript function that returns a Josephus permutation, taking as parameters the initial array/list of items to be permuted as if they were in a circle and counted out every k places until none remained.
How It Works
For example, with n=7 and k=3, josephus(7,3) should act this way:
[1,2,3,4,5,6,7] ? initial sequence [1,2,4,5,6,7] => 3 is counted out and goes into the result [3] [1,2,4,5,7] => 6 is counted out and goes into the result [3,6] [1,4,5,7] => 2 is counted out and goes into the result [3,6,2] [1,4,5] => 7 is counted out and goes into the result [3,6,2,7] [1,4] => 5 is counted out and goes into the result [3,6,2,7,5] [4] => 1 is counted out and goes into the result [3,6,2,7,5,1] [] => 4 is counted out and goes into the result [3,6,2,7,5,1,4]
Therefore, our final result is:
josephus([1,2,3,4,5,6,7],3)==[3,6,2,7,5,1,4];
Implementation Using Recursion with Memoization
The following solution uses a mathematical approach with recursion and memoization for efficiency:
const arr = [1, 2, 3, 4, 5, 6, 7];
const num = 3;
const helper = (n, k, i, map) => {
if (map.hasOwnProperty([n, k, i]))
return map[[n, k, i]];
if (i === 1)
return map[[n, k, i]] = (k - 1) % n;
return map[[n, k, i]] =
(k + helper(n - 1, k, i - 1, map)) % n;
}
const josephus = (arr, k) => {
let n = arr.length;
let result = new Array(n);
let map = {};
for (let i = 1; i
[
3, 6, 2, 7,
5, 1, 4
]
Alternative Iterative Approach
Here's a more intuitive iterative solution that simulates the elimination process:
const josephusIterative = (arr, k) => {
let people = [...arr]; // Create a copy
let result = [];
let currentIndex = 0;
while (people.length > 0) {
// Move k-1 positions (since we count from current position)
currentIndex = (currentIndex + k - 1) % people.length;
// Remove the person at current position and add to result
result.push(people.splice(currentIndex, 1)[0]);
// After removal, currentIndex might need adjustment
if (currentIndex >= people.length) {
currentIndex = 0;
}
}
return result;
};
console.log("Iterative approach:");
console.log(josephusIterative([1, 2, 3, 4, 5, 6, 7], 3));
Iterative approach:
[
3, 6, 2, 7,
5, 1, 4
]
Comparison of Approaches
| Method | Time Complexity | Space Complexity | Readability |
|---|---|---|---|
| Recursive with Memoization | O(n) | O(n) | Complex |
| Iterative Simulation | O(n²) | O(n) | High |
Conclusion
The Josephus problem can be solved efficiently using mathematical recursion with memoization for optimal performance, or with an intuitive iterative approach for better code readability. Choose based on your performance requirements and code maintainability needs.
