All Permutations of a String with distinct characters
Problem
Given a string s that contains no duplicate characters, generate all permutations of s. Return or print each permutation. For a string of length n there are n! permutations.
Examples
Example 1
Input: s = "abc"
Output: ["abc", "acb", "bac", "bca", "cab", "cba"]
Solution
Below are common approaches to generate all permutations when input values are distinct.
Method 1 — Prefix recursion (build-up)
Intuition
Fix a prefix prefix and recursively generate permutations of the remaining characters rest. Appending each character from rest to prefix produces permutations that start with that character.
Approach
- If
restis empty,prefixis a complete permutation — output it. - Otherwise, for each index
iinrest:- Choose
rest[i], append it toprefixand recurse onrestwithoutrest[i].
- Choose
- This explores all
n!permutations.
Edge cases:
- Empty string -> single permutation
"". - Very large
nwill produce huge output (n!) and is impractical to store; stream/print as generated.
Code
C++
class Solution {
public:
// public entry point
std::vector<std::string> permute(const std::string &s) {
return permutePrefix("", s);
}
private:
std::vector<std::string> permutePrefix(const std::string &prefix, const std::string &rest) {
if (rest.empty()) return {prefix};
std::vector<std::string> res;
for (size_t i = 0; i < rest.size(); ++i) {
std::string next_prefix = prefix + rest[i];
std::string next_rest = rest.substr(0, i) + rest.substr(i + 1);
auto sub = permutePrefix(next_prefix, next_rest);
res.insert(res.end(), sub.begin(), sub.end());
}
return res;
}
};
Go
package main
func permutePrefix(prefix, rest string) []string {
if len(rest) == 0 {
return []string{prefix}
}
var res []string
for i := 0; i < len(rest); i++ {
nextPrefix := prefix + string(rest[i])
nextRest := rest[:i] + rest[i+1:]
sub := permutePrefix(nextPrefix, nextRest)
res = append(res, sub...)
}
return res
}
// single-argument entry point
func Permute(s string) []string {
return permutePrefix("", s)
}
Java
class Solution {
public List<String> permute(String s) {
return permutePrefix("", s);
}
private List<String> permutePrefix(String prefix, String rest) {
if (rest.length() == 0) return Collections.singletonList(prefix);
List<String> res = new ArrayList<>();
for (int i = 0; i < rest.length(); ++i) {
String nextPrefix = prefix + rest.charAt(i);
String nextRest = rest.substring(0, i) + rest.substring(i + 1);
res.addAll(permutePrefix(nextPrefix, nextRest));
}
return res;
}
}
Python
class Solution:
def permute_prefix(self, prefix: str, rest: str) -> list[str]:
if not rest:
return [prefix]
res: list[str] = []
for i in range(len(rest)):
next_prefix = prefix + rest[i]
next_rest = rest[:i] + rest[i+1:]
res.extend(self.permute_prefix(next_prefix, next_rest))
return res
def permute(self, s: str) -> list[str]:
return self.permute_prefix("", s)
Complexity
- ⏰ Time complexity:
O(n * n!)— generatingn!permutations and constructing each permutation of lengthn. - 🧺 Space complexity:
O(n)extra space for recursion stack (plus output sizeO(n * n!)if all permutations are stored).
Method 2 — In-place backtracking (swap)
Intuition
Fix a position index and swap each character from index..n-1 into that position, then recurse for index + 1. After recursion, swap back to restore the array (backtracking).
Approach
- Convert string to a mutable array
a. - Define
backtrack(a, index):- If
index == len(a): printaas a permutation. - For
ifromindextolen(a)-1: swapa[index]anda[i], recursebacktrack(a, index+1), swap back.
- If
Edge cases:
- Works in-place and avoids allocating new strings every recursion level, reducing temporary allocations.
Code
C++
class Solution {
public:
std::vector<std::string> permute(std::string a) {
return backtrack(a, 0);
}
private:
std::vector<std::string> backtrack(std::string &a, int index) {
if (index == (int)a.size()) return {a};
std::vector<std::string> res;
for (int i = index; i < (int)a.size(); ++i) {
std::swap(a[index], a[i]);
auto sub = backtrack(a, index + 1);
res.insert(res.end(), sub.begin(), sub.end());
std::swap(a[index], a[i]);
}
return res;
}
};
Go
package main
func backtrack(a []rune, index int) []string {
if index == len(a) {
return []string{string(a)}
}
var res []string
for i := index; i < len(a); i++ {
a[index], a[i] = a[i], a[index]
sub := backtrack(a, index+1)
res = append(res, sub...)
a[index], a[i] = a[i], a[index]
}
return res
}
Java
class Solution {
public List<String> permute(String s) {
return backtrack(s.toCharArray(), 0);
}
private List<String> backtrack(char[] a, int index) {
if (index == a.length) return Collections.singletonList(new String(a));
List<String> res = new ArrayList<>();
for (int i = index; i < a.length; ++i) {
char tmp = a[index]; a[index] = a[i]; a[i] = tmp;
res.addAll(backtrack(a, index + 1));
tmp = a[index]; a[index] = a[i]; a[i] = tmp;
}
return res;
}
}
Python
class Solution:
def permute(self, s: str) -> list[str]:
return self.backtrack(list(s), 0)
def backtrack(self, a: list[str], index: int) -> list[str]:
if index == len(a):
return [''.join(a)]
res: list[str] = []
for i in range(index, len(a)):
a[index], a[i] = a[i], a[index]
res.extend(self.backtrack(a, index + 1))
a[index], a[i] = a[i], a[index]
return res
Complexity
- ⏰ Time complexity:
O(n * n!). - 🧺 Space complexity:
O(n)recursion depth; additionalO(1)extra beyond input.
Method 3 — Iterative using lexicographic next_permutation
Intuition
If you produce permutations in lexicographic order (starting with a sorted string), the next_permutation operation transforms the current permutation into the next one in O(n) time per permutation.
Approach
- Sort the characters of
s. - Output the current permutation.
- Repeatedly apply
next_permutationuntil no next permutation exists.
Code
C++
class Solution {
public:
std::vector<std::string> permute(std::string s) {
std::sort(s.begin(), s.end());
std::vector<std::string> res;
do {
res.push_back(s);
} while (std::next_permutation(s.begin(), s.end()));
return res;
}
};
Go
package main
import "sort"
func nextPermutation(a []rune) bool {
i := len(a) - 2
for i >= 0 && a[i] >= a[i+1] {
i--
}
if i < 0 {
return false
}
j := len(a) - 1
for a[j] <= a[i] {
j--
}
a[i], a[j] = a[j], a[i]
for l, r := i+1, len(a)-1; l < r; l, r = l+1, r-1 {
a[l], a[r] = a[r], a[l]
}
return true
}
func iterative(s string) []string {
a := []rune(s)
sort.Slice(a, func(i, j int) bool { return a[i] < a[j] })
var res []string
for {
res = append(res, string(a))
if !nextPermutation(a) {
break
}
}
return res
}
Java
import java.util.*;
class Solution {
public List<String> permute(String s) {
char[] a = s.toCharArray();
Arrays.sort(a);
List<String> res = new ArrayList<>();
do {
res.add(new String(a));
} while (nextPermutation(a));
return res;
}
private boolean nextPermutation(char[] a) {
int i = a.length - 2;
while (i >= 0 && a[i] >= a[i+1]) i--;
if (i < 0) return false;
int j = a.length - 1;
while (a[j] <= a[i]) j--;
char tmp = a[i]; a[i] = a[j]; a[j] = tmp;
for (int l = i+1, r = a.length-1; l < r; l++, r--) {
tmp = a[l]; a[l] = a[r]; a[r] = tmp;
}
return true;
}
}
Python
import itertools
class Solution:
class Solution:
def permute(self, s: str) -> list[str]:
return [''.join(p) for p in itertools.permutations(s)]
Complexity
- ⏰ Time complexity:
O(n * n!)overall;next_permutationcostsO(n)per permutation. - 🧺 Space complexity:
O(n)extra space.