diff --git a/src/main/java/com/thealgorithms/recursion/Permutations.java b/src/main/java/com/thealgorithms/recursion/Permutations.java new file mode 100644 index 000000000000..5550a0dba5fd --- /dev/null +++ b/src/main/java/com/thealgorithms/recursion/Permutations.java @@ -0,0 +1,84 @@ +package com.thealgorithms.recursion; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * This class provides methods to generate all permutations + * of a given array of any type using recursion. + *
+ * Reference:
+ * https://en.wikipedia.org/wiki/Permutation
+ */
+public final class Permutations {
+
+ private Permutations() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Generates all permutations of a generic array.
+ *
+ * @param > permutations(T[] items) {
+ if (items == null) {
+ throw new NullPointerException("Input array cannot be null");
+ }
+ for (T item : items) {
+ if (item == null) {
+ throw new IllegalArgumentException("Array elements cannot be null");
+ }
+ }
+
+ List
> result = new ArrayList<>();
+ List
> result) {
+ if (index == list.size()) {
+ result.add(new ArrayList<>(list));
+ return;
+ }
+
+ Set
> result = Permutations.permutations(items);
+ assertEquals(1, result.size());
+ assertTrue(result.get(0).isEmpty());
+ }
+
+ @Test
+ void testSingleElementReturnsOnePermutation() {
+ Integer[] items = {42};
+ List
> result = Permutations.permutations(items);
+ assertEquals(1, result.size());
+ assertEquals(List.of(42), result.get(0));
+ }
+
+ // ─────────────────────────────────────────────
+ // Integer Permutation Tests
+ // ─────────────────────────────────────────────
+
+ @Test
+ void testTwoIntegersReturnsTwoPermutations() {
+ Integer[] items = {1, 2};
+ List
> result = Permutations.permutations(items);
+ assertEquals(2, result.size());
+ assertTrue(result.contains(List.of(1, 2)));
+ assertTrue(result.contains(List.of(2, 1)));
+ }
+
+ @Test
+ void testThreeIntegersReturnsSixPermutations() {
+ Integer[] items = {1, 2, 3};
+ List
> result = Permutations.permutations(items);
+ assertEquals(6, result.size());
+ }
+
+ @Test
+ void testIntegerPermutationsContainAllExpectedOrders() {
+ Integer[] items = {1, 2, 3};
+ List
> result = Permutations.permutations(items);
+ assertTrue(result.contains(List.of(1, 2, 3)));
+ assertTrue(result.contains(List.of(1, 3, 2)));
+ assertTrue(result.contains(List.of(2, 1, 3)));
+ assertTrue(result.contains(List.of(2, 3, 1)));
+ assertTrue(result.contains(List.of(3, 1, 2)));
+ assertTrue(result.contains(List.of(3, 2, 1)));
+ }
+
+ // ─────────────────────────────────────────────
+ // Duplicate Handling Tests
+ // ─────────────────────────────────────────────
+
+ @Test
+ void testTwoDuplicateIntegersReturnsOnePermutation() {
+ Integer[] items = {1, 1};
+ List
> result = Permutations.permutations(items);
+ assertEquals(1, result.size());
+ assertEquals(List.of(1, 1), result.get(0));
+ }
+
+ @Test
+ void testArrayWithDuplicatesReturnsCorrectCount() {
+ Integer[] items = {1, 1, 2};
+ List
> result = Permutations.permutations(items);
+ // 3!/2! = 3 unique permutations
+ assertEquals(3, result.size());
+ assertTrue(result.contains(List.of(1, 1, 2)));
+ assertTrue(result.contains(List.of(1, 2, 1)));
+ assertTrue(result.contains(List.of(2, 1, 1)));
+ }
+
+ @Test
+ void testAllDuplicatesReturnsOnePermutation() {
+ Integer[] items = {5, 5, 5};
+ List
> result = Permutations.permutations(items);
+ assertEquals(1, result.size());
+ assertEquals(List.of(5, 5, 5), result.get(0));
+ }
+
+ // ─────────────────────────────────────────────
+ // String Permutation Tests
+ // ─────────────────────────────────────────────
+
+ @Test
+ void testTwoStringsReturnsTwoPermutations() {
+ String[] items = {"a", "b"};
+ List
> result = Permutations.permutations(items);
+ assertEquals(2, result.size());
+ assertTrue(result.contains(List.of("a", "b")));
+ assertTrue(result.contains(List.of("b", "a")));
+ }
+
+ @Test
+ void testThreeStringsReturnsSixPermutations() {
+ String[] items = {"x", "y", "z"};
+ List
> result = Permutations.permutations(items);
+ assertEquals(6, result.size());
+ }
+
+ @Test
+ void testDuplicateStringsReturnsCorrectCount() {
+ String[] items = {"a", "a", "b"};
+ List
> result = Permutations.permutations(items);
+ assertEquals(3, result.size());
+ assertTrue(result.contains(List.of("a", "a", "b")));
+ assertTrue(result.contains(List.of("a", "b", "a")));
+ assertTrue(result.contains(List.of("b", "a", "a")));
+ }
+
+ // ─────────────────────────────────────────────
+ // Character Permutation Tests
+ // ─────────────────────────────────────────────
+
+ @Test
+ void testCharacterPermutations() {
+ Character[] items = {'a', 'b', 'c'};
+ List
> result = Permutations.permutations(items);
+ assertEquals(6, result.size());
+ }
+
+ @Test
+ void testDuplicateCharactersReturnsCorrectCount() {
+ Character[] items = {'a', 'a', 'b'};
+ List
> result = Permutations.permutations(items);
+ assertEquals(3, result.size());
+ }
+}