From d7b60be7d1e1f9805fe54d54d8d4fb0ab0efde98 Mon Sep 17 00:00:00 2001
From: Alex Klymenko
Date: Fri, 23 Aug 2024 11:33:41 +0200
Subject: [PATCH] refactor: `PermuteString` (#5362)
---
.../thealgorithms/strings/PermuteString.java | 108 ++++++++++++------
.../strings/PermuteStringTest.java | 29 +++++
2 files changed, 102 insertions(+), 35 deletions(-)
create mode 100644 src/test/java/com/thealgorithms/strings/PermuteStringTest.java
diff --git a/src/main/java/com/thealgorithms/strings/PermuteString.java b/src/main/java/com/thealgorithms/strings/PermuteString.java
index f263292e..124bdb62 100644
--- a/src/main/java/com/thealgorithms/strings/PermuteString.java
+++ b/src/main/java/com/thealgorithms/strings/PermuteString.java
@@ -1,51 +1,89 @@
package com.thealgorithms.strings;
-/*
-Backtracking algorithm used in the program:-
+import java.util.HashSet;
+import java.util.Set;
->>Fix a character in the first position and swap the rest of the character with the first character.
- Like in ABC, in the first iteration three strings are formed: ABC, BAC, and CBA by swapping A with
- A, B and C respectively.
->>Repeat step 1 for the rest of the characters like fixing second character B and so on.
->>Now swap again to go back to the previous position. E.g., from ABC, we formed ABC by fixing B
-again, and we backtrack to the previous position and swap B with C. So, now we got ABC and ACB.
->>Repeat these steps for BAC and CBA, to get all the permutations.
+/**
+ * This class provides methods for generating all permutations of a given string using a backtracking algorithm.
+ *
+ * The algorithm works as follows:
+ *
+ * - Fix a character in the current position and swap it with each of the remaining characters.
+ * For example, for the string "ABC":
+ *
+ * - Fix 'A' at the first position: permutations are "ABC", "BAC", "CBA" (obtained by swapping 'A' with 'B' and 'C' respectively).
+ *
+ *
+ * - Repeat the process for the next character.
+ * For instance, after fixing 'B' in the second position:
+ *
+ * - For "BAC", the permutations include "BAC" and "BCA" (after swapping 'A' and 'C').
+ *
+ *
+ * - After generating permutations for the current position, backtrack by swapping the characters back to their original positions to restore the state.
+ * For example, after generating permutations for "ABC", swap back to restore "BAC" and continue with further permutations.
+ * - Repeat the process for all characters to get all possible permutations.
+ *
+ *
*/
public final class PermuteString {
private PermuteString() {
}
- // Function for swapping the characters at position I with character at position j
- public static String swapString(String a, int i, int j) {
- char[] b = a.toCharArray();
- char ch;
- ch = b[i];
- b[i] = b[j];
- b[j] = ch;
- return String.valueOf(b);
+ /**
+ * Generates all possible permutations of the given string.
+ *
+ * This method returns a set containing all unique permutations of the input string. It leverages
+ * a recursive helper method to generate these permutations.
+ *
+ * @param str The input string for which permutations are to be generated.
+ * If the string is null or empty, the result will be an empty set.
+ * @return A {@link Set} of strings containing all unique permutations of the input string.
+ * If the input string has duplicate characters, the set will ensure that only unique permutations
+ * are returned.
+ */
+ public static Set getPermutations(String str) {
+ Set permutations = new HashSet<>();
+ generatePermutations(str, 0, str.length(), permutations);
+ return permutations;
}
- public static void main(String[] args) {
- String str = "ABC";
- int len = str.length();
- System.out.println("All the permutations of the string are: ");
- generatePermutation(str, 0, len);
- }
-
- // Function for generating different permutations of the string
- public static void generatePermutation(String str, int start, int end) {
- // Prints the permutations
+ /**
+ * Generates all permutations of the given string and collects them into a set.
+ *
+ * @param str the string to permute
+ * @param start the starting index for the current permutation
+ * @param end the end index (length of the string)
+ * @param permutations the set to collect all unique permutations
+ */
+ private static void generatePermutations(String str, int start, int end, Set permutations) {
if (start == end - 1) {
- System.out.println(str);
+ permutations.add(str);
} else {
- for (int i = start; i < end; i++) {
- // Swapping the string by fixing a character
- str = swapString(str, start, i);
- // Recursively calling function generatePermutation() for rest of the characters
- generatePermutation(str, start + 1, end);
- // Backtracking and swapping the characters again.
- str = swapString(str, start, i);
+ for (int currentIndex = start; currentIndex < end; currentIndex++) {
+ // Swap the current character with the character at the start index
+ str = swapCharacters(str, start, currentIndex);
+ // Recursively generate permutations for the remaining characters
+ generatePermutations(str, start + 1, end, permutations);
+ // Backtrack: swap the characters back to their original positions
+ str = swapCharacters(str, start, currentIndex);
}
}
}
+
+ /**
+ * Swaps the characters at the specified positions in the given string.
+ *
+ * @param str the string in which characters will be swapped
+ * @param i the position of the first character to swap
+ * @param j the position of the second character to swap
+ * @return a new string with the characters at positions i and j swapped
+ */
+ private static String swapCharacters(String str, int i, int j) {
+ char[] chars = str.toCharArray();
+ char temp = chars[i];
+ chars[i] = chars[j];
+ chars[j] = temp;
+ return new String(chars);
+ }
}
diff --git a/src/test/java/com/thealgorithms/strings/PermuteStringTest.java b/src/test/java/com/thealgorithms/strings/PermuteStringTest.java
new file mode 100644
index 00000000..c726874f
--- /dev/null
+++ b/src/test/java/com/thealgorithms/strings/PermuteStringTest.java
@@ -0,0 +1,29 @@
+package com.thealgorithms.strings;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Set;
+import java.util.stream.Stream;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class PermuteStringTest {
+
+ private static Stream provideTestCases() {
+ 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")),
+ 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!")),
+ 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")),
+ new TestData("A B", Set.of("A B", "AB ", " AB", " BA", "BA ", "B A")),
+ 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")));
+ }
+
+ @ParameterizedTest
+ @MethodSource("provideTestCases")
+ void testPermutations(TestData testData) {
+ Set actualPermutations = PermuteString.getPermutations(testData.input);
+ assertEquals(testData.expected, actualPermutations, "The permutations of '" + testData.input + "' are not correct.");
+ }
+
+ record TestData(String input, Set expected) {
+ }
+}