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: + *

    + *
  1. 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).
    • + *
    + *
  2. + *
  3. 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').
    • + *
    + *
  4. + *
  5. 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.
  6. + *
  7. Repeat the process for all characters to get all possible permutations.
  8. + *
+ *

*/ 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) { + } +}