Skip to content

Commit d7b60be

Browse files
authored
refactor: PermuteString (#5362)
1 parent 0301ecf commit d7b60be

File tree

2 files changed

+102
-35
lines changed

2 files changed

+102
-35
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,89 @@
11
package com.thealgorithms.strings;
22

3-
/*
4-
Backtracking algorithm used in the program:-
3+
import java.util.HashSet;
4+
import java.util.Set;
55

6-
>>Fix a character in the first position and swap the rest of the character with the first character.
7-
Like in ABC, in the first iteration three strings are formed: ABC, BAC, and CBA by swapping A with
8-
A, B and C respectively.
9-
>>Repeat step 1 for the rest of the characters like fixing second character B and so on.
10-
>>Now swap again to go back to the previous position. E.g., from ABC, we formed ABC by fixing B
11-
again, and we backtrack to the previous position and swap B with C. So, now we got ABC and ACB.
12-
>>Repeat these steps for BAC and CBA, to get all the permutations.
6+
/**
7+
* This class provides methods for generating all permutations of a given string using a backtracking algorithm.
8+
* <p>
9+
* The algorithm works as follows:
10+
* <ol>
11+
* <li>Fix a character in the current position and swap it with each of the remaining characters.
12+
* For example, for the string "ABC":
13+
* <ul>
14+
* <li>Fix 'A' at the first position: permutations are "ABC", "BAC", "CBA" (obtained by swapping 'A' with 'B' and 'C' respectively).</li>
15+
* </ul>
16+
* </li>
17+
* <li>Repeat the process for the next character.
18+
* For instance, after fixing 'B' in the second position:
19+
* <ul>
20+
* <li>For "BAC", the permutations include "BAC" and "BCA" (after swapping 'A' and 'C').</li>
21+
* </ul>
22+
* </li>
23+
* <li>After generating permutations for the current position, backtrack by swapping the characters back to their original positions to restore the state.
24+
* For example, after generating permutations for "ABC", swap back to restore "BAC" and continue with further permutations.</li>
25+
* <li>Repeat the process for all characters to get all possible permutations.</li>
26+
* </ol>
27+
* </p>
1328
*/
1429
public final class PermuteString {
1530
private PermuteString() {
1631
}
1732

18-
// Function for swapping the characters at position I with character at position j
19-
public static String swapString(String a, int i, int j) {
20-
char[] b = a.toCharArray();
21-
char ch;
22-
ch = b[i];
23-
b[i] = b[j];
24-
b[j] = ch;
25-
return String.valueOf(b);
33+
/**
34+
* Generates all possible permutations of the given string.
35+
*
36+
* <p>This method returns a set containing all unique permutations of the input string. It leverages
37+
* a recursive helper method to generate these permutations.
38+
*
39+
* @param str The input string for which permutations are to be generated.
40+
* If the string is null or empty, the result will be an empty set.
41+
* @return A {@link Set} of strings containing all unique permutations of the input string.
42+
* If the input string has duplicate characters, the set will ensure that only unique permutations
43+
* are returned.
44+
*/
45+
public static Set<String> getPermutations(String str) {
46+
Set<String> permutations = new HashSet<>();
47+
generatePermutations(str, 0, str.length(), permutations);
48+
return permutations;
2649
}
2750

28-
public static void main(String[] args) {
29-
String str = "ABC";
30-
int len = str.length();
31-
System.out.println("All the permutations of the string are: ");
32-
generatePermutation(str, 0, len);
33-
}
34-
35-
// Function for generating different permutations of the string
36-
public static void generatePermutation(String str, int start, int end) {
37-
// Prints the permutations
51+
/**
52+
* Generates all permutations of the given string and collects them into a set.
53+
*
54+
* @param str the string to permute
55+
* @param start the starting index for the current permutation
56+
* @param end the end index (length of the string)
57+
* @param permutations the set to collect all unique permutations
58+
*/
59+
private static void generatePermutations(String str, int start, int end, Set<String> permutations) {
3860
if (start == end - 1) {
39-
System.out.println(str);
61+
permutations.add(str);
4062
} else {
41-
for (int i = start; i < end; i++) {
42-
// Swapping the string by fixing a character
43-
str = swapString(str, start, i);
44-
// Recursively calling function generatePermutation() for rest of the characters
45-
generatePermutation(str, start + 1, end);
46-
// Backtracking and swapping the characters again.
47-
str = swapString(str, start, i);
63+
for (int currentIndex = start; currentIndex < end; currentIndex++) {
64+
// Swap the current character with the character at the start index
65+
str = swapCharacters(str, start, currentIndex);
66+
// Recursively generate permutations for the remaining characters
67+
generatePermutations(str, start + 1, end, permutations);
68+
// Backtrack: swap the characters back to their original positions
69+
str = swapCharacters(str, start, currentIndex);
4870
}
4971
}
5072
}
73+
74+
/**
75+
* Swaps the characters at the specified positions in the given string.
76+
*
77+
* @param str the string in which characters will be swapped
78+
* @param i the position of the first character to swap
79+
* @param j the position of the second character to swap
80+
* @return a new string with the characters at positions i and j swapped
81+
*/
82+
private static String swapCharacters(String str, int i, int j) {
83+
char[] chars = str.toCharArray();
84+
char temp = chars[i];
85+
chars[i] = chars[j];
86+
chars[j] = temp;
87+
return new String(chars);
88+
}
5189
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.thealgorithms.strings;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.Set;
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
10+
public class PermuteStringTest {
11+
12+
private static Stream<TestData> provideTestCases() {
13+
return Stream.of(new TestData("ABC", Set.of("ABC", "ACB", "BAC", "BCA", "CAB", "CBA")), new TestData("AB", Set.of("AB", "BA")), new TestData("A", Set.of("A")), new TestData("AA", Set.of("AA")), new TestData("123", Set.of("123", "132", "213", "231", "312", "321")),
14+
new TestData("aA", Set.of("aA", "Aa")), new TestData("AaB", Set.of("AaB", "ABa", "aAB", "aBA", "BAa", "BaA")), new TestData("!@", Set.of("!@", "@!")), new TestData("!a@", Set.of("!a@", "!@a", "a!@", "a@!", "@!a", "@a!")),
15+
new TestData("ABCD", Set.of("ABCD", "ABDC", "ACBD", "ACDB", "ADBC", "ADCB", "BACD", "BADC", "BCAD", "BCDA", "BDAC", "BDCA", "CABD", "CADB", "CBAD", "CBDA", "CDAB", "CDBA", "DABC", "DACB", "DBAC", "DBCA", "DCAB", "DCBA")),
16+
new TestData("A B", Set.of("A B", "AB ", " AB", " BA", "BA ", "B A")),
17+
new TestData("abcd", Set.of("abcd", "abdc", "acbd", "acdb", "adbc", "adcb", "bacd", "badc", "bcad", "bcda", "bdac", "bdca", "cabd", "cadb", "cbad", "cbda", "cdab", "cdba", "dabc", "dacb", "dbac", "dbca", "dcab", "dcba")));
18+
}
19+
20+
@ParameterizedTest
21+
@MethodSource("provideTestCases")
22+
void testPermutations(TestData testData) {
23+
Set<String> actualPermutations = PermuteString.getPermutations(testData.input);
24+
assertEquals(testData.expected, actualPermutations, "The permutations of '" + testData.input + "' are not correct.");
25+
}
26+
27+
record TestData(String input, Set<String> expected) {
28+
}
29+
}

0 commit comments

Comments
 (0)