Skip to content

Commit 8b89e9d

Browse files
committed
Add unique permutation algorithm and test cases
1 parent 1c97ad8 commit 8b89e9d

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.List;
6+
7+
/**
8+
* Generates all UNIQUE permutations of a string, even when duplicate characters exist.
9+
*
10+
* Example:
11+
* Input: "AAB"
12+
* Output: ["AAB", "ABA", "BAA"]
13+
*
14+
* Time Complexity: O(n! * n)
15+
*/
16+
public final class UniquePermutation {
17+
18+
private UniquePermutation() {
19+
// Prevent instantiation
20+
throw new UnsupportedOperationException("Utility class");
21+
}
22+
23+
public static List<String> generateUniquePermutations(String input) {
24+
List<String> result = new ArrayList<>();
25+
if (input == null) return result;
26+
27+
char[] chars = input.toCharArray();
28+
Arrays.sort(chars); // important: sort to detect duplicates
29+
30+
backtrack(chars, new boolean[chars.length], new StringBuilder(), result);
31+
return result;
32+
}
33+
34+
private static void backtrack(char[] chars, boolean[] used, StringBuilder current, List<String> result) {
35+
36+
if (current.length() == chars.length) {
37+
result.add(current.toString());
38+
return;
39+
}
40+
41+
for (int i = 0; i < chars.length; i++) {
42+
43+
// skip duplicates
44+
if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
45+
continue;
46+
}
47+
48+
if (!used[i]) {
49+
used[i] = true;
50+
current.append(chars[i]);
51+
52+
backtrack(chars, used, current, result);
53+
54+
// undo changes
55+
used[i] = false;
56+
current.deleteCharAt(current.length() - 1);
57+
}
58+
}
59+
}
60+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.Arrays;
6+
import java.util.List;
7+
import org.junit.jupiter.api.Test;
8+
9+
public class UniquePermutationTest {
10+
11+
@Test
12+
void testUniquePermutations_AAB() {
13+
List<String> expected = Arrays.asList("AAB", "ABA", "BAA");
14+
List<String> result = UniquePermutation.generateUniquePermutations("AAB");
15+
assertEquals(expected, result);
16+
}
17+
18+
@Test
19+
void testUniquePermutations_ABC() {
20+
List<String> expected = Arrays.asList("ABC", "ACB", "BAC", "BCA", "CAB", "CBA");
21+
List<String> result = UniquePermutation.generateUniquePermutations("ABC");
22+
assertEquals(expected, result);
23+
}
24+
25+
@Test
26+
void testEmptyString() {
27+
List<String> expected = Arrays.asList("");
28+
List<String> result = UniquePermutation.generateUniquePermutations("");
29+
assertEquals(expected, result);
30+
}
31+
}

0 commit comments

Comments
 (0)