Skip to content

Commit 8c80879

Browse files
committed
Add unique permutation algorithm with test cases
1 parent 1c97ad8 commit 8c80879

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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,
35+
StringBuilder current, List<String> result) {
36+
37+
if (current.length() == chars.length) {
38+
result.add(current.toString());
39+
return;
40+
}
41+
42+
for (int i = 0; i < chars.length; i++) {
43+
44+
// skip duplicates
45+
if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
46+
continue;
47+
}
48+
49+
if (!used[i]) {
50+
used[i] = true;
51+
current.append(chars[i]);
52+
53+
backtrack(chars, used, current, result);
54+
55+
// undo changes
56+
used[i] = false;
57+
current.deleteCharAt(current.length() - 1);
58+
}
59+
}
60+
}
61+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.List;
6+
import java.util.Arrays;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
class UniquePermutationTest {
11+
12+
@Test
13+
void testUniquePermutations_AAB() {
14+
List<String> expected = Arrays.asList("AAB", "ABA", "BAA");
15+
List<String> result = UniquePermutation.generateUniquePermutations("AAB");
16+
assertEquals(expected, result);
17+
}
18+
19+
@Test
20+
void testUniquePermutations_ABC() {
21+
List<String> expected =
22+
Arrays.asList("ABC", "ACB", "BAC", "BCA", "CAB", "CBA");
23+
List<String> result = UniquePermutation.generateUniquePermutations("ABC");
24+
assertEquals(expected, result);
25+
}
26+
27+
@Test
28+
void testEmptyString() {
29+
List<String> expected = Arrays.asList("");
30+
List<String> result = UniquePermutation.generateUniquePermutations("");
31+
assertEquals(expected, result);
32+
}
33+
}
34+

0 commit comments

Comments
 (0)