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#
1
2
Input: s = "abc"
Output: [ "abc" , "acb" , "bac" , "bca" , "cab" , "cba" ]
Similar Problems
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 rest
is empty, prefix
is a complete permutation — output it.
Otherwise, for each index i
in rest
:
Choose rest[i]
, append it to prefix
and recurse on rest
without rest[i]
.
This explores all n!
permutations.
Edge cases:
Empty string -> single permutation ""
.
Very large n
will produce huge output (n!
) and is impractical to store; stream/print as generated.
Code#
Cpp
Go
Java
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 )
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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!)
— generating n!
permutations and constructing each permutation of length n
.
🧺 Space complexity: O(n)
extra space for recursion stack (plus output size O(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)
: print a
as a permutation.
For i
from index
to len(a)-1
: swap a[index]
and a[i]
, recurse backtrack(a, index+1)
, swap back.
Edge cases:
Works in-place and avoids allocating new strings every recursion level, reducing temporary allocations.
Code#
Cpp
Go
Java
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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; additional O(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_permutation
until no next permutation exists.
Code#
Cpp
Go
Java
Python
1
2
3
4
5
6
7
8
9
10
11
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;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 ;
}
}
1
2
3
4
5
6
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_permutation
costs O(n)
per permutation.
🧺 Space complexity: O(n)
extra space.