Skip to content

Commit 4f051e3

Browse files
Added Josephus problem recursive solution and test cases by ritesh-3822
1 parent 69d8406 commit 4f051e3

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package com.thealgorithms.recursion;
2+
3+
/**
4+
* Josephus - Solves the Josephus problem using recursion
5+
*
6+
* The Josephus problem: n people numbered 1..n stand in a circle. Starting from
7+
* position 1, every k-th person is eliminated until one remains. This class
8+
* provides a recursive solution to compute the survivor's position (1-based).
9+
*
10+
* Recurrence (0-based): J(1,k) = 0; J(n,k) = (J(n-1,k) + k) % n
11+
* Convert to 1-based by adding 1.
12+
*
13+
* @author ritesh-3822
14+
* @see <a href="https://en.wikipedia.org/wiki/Josephus_problem">Josephus problem</a>
15+
*/
16+
public final class Josephus {
17+
18+
/**
19+
* Returns the 1-based position of the survivor for given n and k.
20+
*
21+
* @param n number of people (must be > 0)
22+
* @param k step count (must be > 0)
23+
* @return 1-based index of the survivor
24+
* @throws IllegalArgumentException if n <= 0 or k <= 0
25+
*/
26+
public static int getJosephus(int n, int k) {
27+
if (n <= 0) {
28+
throw new IllegalArgumentException("n must be positive");
29+
}
30+
if (k <= 0) {
31+
throw new IllegalArgumentException("k must be positive");
32+
}
33+
// compute zero-based result and convert to 1-based
34+
return josephusZeroBased(n, k) + 1;
35+
}
36+
37+
/**
38+
* Prints the survivor position (1-based) for given n and k.
39+
*
40+
* @param n number of people (must be > 0)
41+
* @param k step count (must be > 0)
42+
* @throws IllegalArgumentException if n <= 0 or k <= 0
43+
*/
44+
public static void printJosephus(int n, int k) {
45+
int survivor = getJosephus(n, k);
46+
System.out.println(survivor);
47+
}
48+
49+
/**
50+
* Recursive helper that returns the zero-based survivor index.
51+
*
52+
* @param n number of people
53+
* @param k step
54+
* @return zero-based survivor index
55+
*/
56+
private static int josephusZeroBased(int n, int k) {
57+
// Base case
58+
if (n == 1) {
59+
return 0;
60+
}
61+
// Recurrence
62+
return (josephusZeroBased(n - 1, k) + k) % n;
63+
}
64+
65+
/**
66+
* Demo method to show usage
67+
*
68+
* @param args command line arguments
69+
*/
70+
public static void main(String[] args) {
71+
int n = 7;
72+
int k = 3;
73+
74+
System.out.println("Josephus problem demo:");
75+
System.out.printf("n = %d, k = %d%n", n, k);
76+
int survivor = getJosephus(n, k);
77+
System.out.println("Survivor (1-based position): " + survivor);
78+
}
79+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.thealgorithms.recursion;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.io.PrintStream;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
import static org.junit.jupiter.api.Assertions.assertThrows;
8+
import static org.junit.jupiter.api.Assertions.assertTrue;
9+
import org.junit.jupiter.api.Test;
10+
11+
/**
12+
* Test class for Josephus problem implementation
13+
*
14+
* @author ritesh-3822
15+
* @see Josephus
16+
*/
17+
class JosephusTest {
18+
19+
@Test
20+
void testNOneAnyK() {
21+
// single person -> survivor is 1
22+
assertEquals(1, Josephus.getJosephus(1, 1));
23+
assertEquals(1, Josephus.getJosephus(1, 5));
24+
assertEquals(1, Josephus.getJosephus(1, 100));
25+
}
26+
27+
@Test
28+
void testSmallCases() {
29+
// Known small results
30+
assertEquals(3, Josephus.getJosephus(5, 2)); // classic: n=5,k=2 -> 3
31+
assertEquals(4, Josephus.getJosephus(7, 3)); // classic: n=7,k=3 -> 4
32+
assertEquals(5, Josephus.getJosephus(10, 2)); // n=10,k=2 -> 5
33+
}
34+
35+
@Test
36+
void testLargerKnown() {
37+
// Known classic example
38+
assertEquals(28, Josephus.getJosephus(40, 3)); // classic result
39+
}
40+
41+
@Test
42+
void testVariousKValues() {
43+
assertEquals(1, Josephus.getJosephus(2, 2)); // persons 1..2, k=2 -> survivor 1
44+
assertEquals(2, Josephus.getJosephus(2, 1)); // k=1 eliminates in order -> last is 2
45+
assertEquals(4, Josephus.getJosephus(8, 3));
46+
}
47+
48+
@Test
49+
void testLargeNPerformance() {
50+
// sanity for large n: should complete quickly (recursive depth = n)
51+
int survivor = Josephus.getJosephus(1000, 7);
52+
assertTrue(survivor >= 1 && survivor <= 1000);
53+
}
54+
55+
@Test
56+
void testInvalidInputs() {
57+
assertThrows(IllegalArgumentException.class, () -> Josephus.getJosephus(0, 3));
58+
assertThrows(IllegalArgumentException.class, () -> Josephus.getJosephus(-5, 2));
59+
assertThrows(IllegalArgumentException.class, () -> Josephus.getJosephus(5, 0));
60+
assertThrows(IllegalArgumentException.class, () -> Josephus.getJosephus(5, -1));
61+
}
62+
63+
@Test
64+
void testPrintJosephus() {
65+
// Capture System.out
66+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
67+
PrintStream originalOut = System.out;
68+
System.setOut(new PrintStream(outputStream));
69+
70+
try {
71+
Josephus.printJosephus(7, 3); // known survivor 4
72+
String output = outputStream.toString().trim();
73+
// output should contain just the survivor number (since printJosephus prints only the number)
74+
assertEquals("4", output);
75+
} finally {
76+
System.setOut(originalOut);
77+
}
78+
}
79+
80+
@Test
81+
void testMainMethodContainsDemo() {
82+
// Capture System.out
83+
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
84+
PrintStream originalOut = System.out;
85+
System.setOut(new PrintStream(outputStream));
86+
87+
try {
88+
Josephus.main(new String[] {});
89+
String output = outputStream.toString();
90+
assertTrue(output.contains("Josephus problem demo:"));
91+
assertTrue(output.contains("Survivor (1-based position):"));
92+
} finally {
93+
System.setOut(originalOut);
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)