The quick way: using itertools

Python’s itertools.permutations handles this in one line:

from itertools import permutations

perms = sorted([''.join(p) for p in set(permutations('hello'))])
print(perms)
print(len(perms))  # 60

This gives all 60 unique permutations of “hello”, sorted alphabetically.

But many coding challenges explicitly say do not use built-in functions. If you need a solution without itertools, read on.

Without built-in functions: recursive approach

This builds permutations from scratch using only recursion and basic string operations:

def permutations(string):
    if len(string) == 1:
        return [string]

    result = []
    for i, char in enumerate(string):
        remaining = string[:i] + string[i+1:]
        for perm in permutations(remaining):
            result.append(char + perm)

    return sorted(set(result))

How it works:

  1. Base case: a single character has only one permutation — itself.
  2. For each character in the string, remove it and recursively find all permutations of what’s left.
  3. Prepend the removed character to each sub-permutation.
  4. Use set() to eliminate duplicates (important for strings with repeated characters like “hello”).
  5. Sort the result alphabetically.
perms = permutations('hello')
print(len(perms))  # 60
print(perms[:5])   # ['ehllo', 'ehlol', 'eholl', 'elhlo', 'ellho']

Returning results in alphabetical order

Both approaches above return results sorted alphabetically. If your challenge requires alphabetical output:

  • With itertools: wrap in sorted()
  • Without itertools: the sorted(set(result)) at the end handles it

If you need to avoid sorted() too, insert each permutation into the result list in order, or sort manually:

def permutations_alphabetical(string):
    chars = sorted(string)  # start with sorted characters
    result = []

    def backtrack(path, remaining):
        if not remaining:
            result.append(path)
            return
        seen = set()
        for i, char in enumerate(remaining):
            if char in seen:
                continue
            seen.add(char)
            backtrack(path + char, remaining[:i] + remaining[i+1:])

    backtrack('', ''.join(chars))
    return result

This backtracking approach generates permutations in alphabetical order directly, without needing to sort afterward. It also skips duplicate characters at each recursion level, making it efficient for strings with repeated letters.

Complexity

  • Time: O(n! × n) — there are n! permutations, each of length n.
  • Space: O(n! × n) to store all results.

For a 10-character string with all unique characters, that’s 3,628,800 permutations. Keep input strings short.

Test cases

assert sorted(permutations('a')) == ['a']
assert sorted(permutations('ab')) == ['ab', 'ba']
assert len(permutations('abc')) == 6
assert len(permutations('hello')) == 60
assert permutations('aab') == ['aab', 'aba', 'baa']

If you enjoyed this, try these similar Python and Java coding puzzles: