StringProblem 11 of 43

Print all the permutations of the given string

Brute Force
Time: O(n! × n)
Space: O(n)
Optimal
Time: O(n! × n)
Space: O(n)

Problem Statement

Given a string, print all permutations of the string. A permutation is a rearrangement of all characters in the string.

Example:

  • Input: "abc"

  • Output: ["abc", "acb", "bac", "bca", "cab", "cba"]

  • Input: "ab"

  • Output: ["ab", "ba"]

Note: A string of length n has n! permutations.


Approach 1: Recursion with Swapping

Intuition

Fix one character at a time and recursively permute the rest. Swap the current character with each subsequent character to generate all permutations.

Algorithm

  1. Start with index 0
  2. Swap current index with each index from current to end
  3. Recurse for the next index
  4. Backtrack by swapping back
java
import java.util.*;

public class Solution {
    public List<String> getPermutations(String s) {
        List<String> result = new ArrayList<>();
        permute(s.toCharArray(), 0, result);
        return result;
    }
    
    private void permute(char[] chars, int index, List<String> result) {
        // Base case: reached end of string
        if (index == chars.length) {
            result.add(new String(chars));
            return;
        }
        
        // Try swapping current position with each subsequent position
        for (int i = index; i < chars.length; i++) {
            swap(chars, index, i);        // Swap
            permute(chars, index + 1, result); // Recurse
            swap(chars, index, i);        // Backtrack
        }
    }
    
    private void swap(char[] chars, int i, int j) {
        char temp = chars[i];
        chars[i] = chars[j];
        chars[j] = temp;
    }
}

Complexity Analysis

  • Time Complexity: O(n! × n) - n! permutations, each taking O(n) to construct
  • Space Complexity: O(n) - Recursion stack depth

Approach 2: Using Visited Array

Intuition

Build permutations character by character. Use a visited array to track which characters have been used in the current permutation.

Algorithm

  1. For each position in the result, try each unused character
  2. Mark the character as used and recurse
  3. Backtrack by unmarking the character
java
import java.util.*;

public class Solution {
    public List<String> getPermutations(String s) {
        List<String> result = new ArrayList<>();
        boolean[] visited = new boolean[s.length()];
        permute(s, "", visited, result);
        return result;
    }
    
    private void permute(String s, String current, boolean[] visited, 
                         List<String> result) {
        if (current.length() == s.length()) {
            result.add(current);
            return;
        }
        
        for (int i = 0; i < s.length(); i++) {
            if (!visited[i]) {
                visited[i] = true;
                permute(s, current + s.charAt(i), visited, result);
                visited[i] = false;
            }
        }
    }
}

Complexity Analysis

  • Time Complexity: O(n! × n)
  • Space Complexity: O(n) - Visited array + recursion stack

Approach 3: Handling Duplicates

Intuition

When the string has duplicate characters, some permutations will be repeated. To avoid duplicates:

  1. Sort the string first
  2. Skip a character if it's the same as the previous one and the previous one hasn't been used in the current path
java
import java.util.*;

public class Solution {
    public List<String> getUniquePermutations(String s) {
        List<String> result = new ArrayList<>();
        char[] chars = s.toCharArray();
        Arrays.sort(chars);
        boolean[] visited = new boolean[chars.length];
        permuteUnique(chars, "", visited, result);
        return result;
    }
    
    private void permuteUnique(char[] chars, String current, boolean[] visited,
                               List<String> result) {
        if (current.length() == chars.length) {
            result.add(current);
            return;
        }
        
        for (int i = 0; i < chars.length; i++) {
            if (visited[i]) continue;
            
            // Skip duplicates
            if (i > 0 && chars[i] == chars[i-1] && !visited[i-1]) continue;
            
            visited[i] = true;
            permuteUnique(chars, current + chars[i], visited, result);
            visited[i] = false;
        }
    }
}

Complexity Analysis

  • Time Complexity: O(n! × n) in worst case (all unique characters)
  • Space Complexity: O(n)

Approach 4: Next Permutation (Iterative)

Intuition

Generate permutations in lexicographic order using the next permutation algorithm. This approach doesn't use recursion.


Key Takeaways

  1. n! permutations exist for a string of length n
  2. Swapping approach is most common and efficient for unique characters
  3. Visited array approach is cleaner but uses extra space
  4. For duplicates, sort first and skip repeated characters
  5. Next permutation provides an iterative solution
  6. Time complexity is unavoidably O(n!) since output is factorial
  7. This is a classic backtracking problem
  8. The swapping technique maintains the original order of untouched elements