diff --git a/src/main/java/com/thealgorithms/Recursion/UniquePermutations.java b/src/main/java/com/thealgorithms/Recursion/UniquePermutations.java new file mode 100644 index 000000000000..b11bdae9b781 --- /dev/null +++ b/src/main/java/com/thealgorithms/Recursion/UniquePermutations.java @@ -0,0 +1,52 @@ +package com.thealgorithms.Recursion; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class UniquePermutations { + + public static List getUniquePermutations(String str) { + // Handle null or empty input + if (str == null) return new ArrayList<>(); + if (str.length() == 0) { + List result = new ArrayList<>(); + result.add(""); + return result; + } + + // Sort characters to handle duplicates + char[] chars = str.toCharArray(); + Arrays.sort(chars); + + List result = new ArrayList<>(); + boolean[] used = new boolean[chars.length]; + StringBuilder currentPermutation = new StringBuilder(); + generatePermutations(chars, used, currentPermutation, result); + return result; + } + + private static void generatePermutations(char[] chars, boolean[] used, StringBuilder currentPermutation, List result) { + if (currentPermutation.length() == chars.length) { + result.add(currentPermutation.toString()); + return; + } + + for (int i = 0; i < chars.length; i++) { + // Skip used characters or duplicates + if (used[i] || (i > 0 && chars[i] == chars[i - 1] && !used[i - 1])) { + continue; + } + used[i] = true; + currentPermutation.append(chars[i]); + generatePermutations(chars, used, currentPermutation, result); + used[i] = false; + currentPermutation.deleteCharAt(currentPermutation.length() - 1); + } + } +} + + +//This is a more efficient but complex algorithm +//If you want to refer to a simpler one and then come to this, +//click on the URL=>"https://www.geeksforgeeks.org/java-program-to-print-distinct-permutations-of-a-string/"" diff --git a/src/test/java/com/thealgorithms/Recursion/UniquePermutationsTest.java b/src/test/java/com/thealgorithms/Recursion/UniquePermutationsTest.java new file mode 100644 index 000000000000..34a56996166c --- /dev/null +++ b/src/test/java/com/thealgorithms/Recursion/UniquePermutationsTest.java @@ -0,0 +1,72 @@ +package com.thealgorithms.Recursion; + +import org.junit.jupiter.api.Test; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class UniquePermutationsTest { + + @Test + void testUniquePermutations() { + String str = "abc"; + List expected = List.of("abc", "acb", "bac", "bca", "cab", "cba"); + List result = UniquePermutations.getUniquePermutations(str); + Collections.sort(expected); // Ensure expected is sorted + Collections.sort(result); // Ensure result is sorted + assertEquals(expected, result); + } + + @Test + void testUniquePermutationsWithDuplicates() { + String str = "aab"; + List expected = List.of("aab", "aba", "baa"); + List result = UniquePermutations.getUniquePermutations(str); + Collections.sort(expected); // Ensure expected is sorted + Collections.sort(result); // Ensure result is sorted + assertEquals(expected, result); + } + + @Test + void testEmptyString() { + String str = ""; + List result = UniquePermutations.getUniquePermutations(str); + assertEquals(1, result.size()); // only 1 permutation which is an empty string + assertEquals("", result.get(0)); // Verify the only permutation is the empty string + } + + @Test + void testSingleCharacter() { + String str = "a"; + List result = UniquePermutations.getUniquePermutations(str); + assertEquals(1, result.size()); + assertEquals("a", result.get(0)); + } + + @Test + void testAllIdenticalCharacters() { + String str = "aaa"; + List expected = List.of("aaa"); + List result = UniquePermutations.getUniquePermutations(str); + assertEquals(expected.size(), result.size()); + assertEquals(expected, result); + } + + @Test + void testMixedCaseCharacters() { + String str = "aAb"; + List expected = List.of("AaB", "AbA", "aAB", "aBA", "baA", "bAa"); + List result = UniquePermutations.getUniquePermutations(str); + Collections.sort(expected); // Ensure expected is sorted + Collections.sort(result); // Ensure result is sorted + assertEquals(expected, result); + } + + @Test + void testNullInput() { + String str = null; + List result = UniquePermutations.getUniquePermutations(str); + assertEquals(0, result.size()); // Expect an empty list for null input + } +}