Python Program to Print All Permutations
Intermediate Backtracking Time O(n ร n!) Space O(n)
Lists every ordering of a list's items by choosing an item for each place in turn, then undoing the choice to try the next one.
A permutation is one ordering of a set of items. The letters A, B and C can be ordered in 3 ร 2 ร 1 = 6 ways: ABC, ACB, BAC, BCA, CAB and CBA. Four items have 24 orderings, and n items have n! ("n factorial").
The program builds the orderings by backtracking: it chooses an item for the first place, then one of the items left for the next place, and so on. When the ordering is full it saves it, then undoes the last choice and tries the next item in that place. Choose, explore, undo: that pattern is behind every backtracking program.
Program
def permutations(items):
"""Every ordering of items, as a list of lists."""
result = []
current = []
used = [False] * len(items)
def backtrack():
if len(current) == len(items):
result.append(current.copy())
return
for i, item in enumerate(items):
if not used[i]:
used[i] = True # choose this item
current.append(item)
backtrack() # fill the places after it
current.pop() # undo the choice
used[i] = False
backtrack()
return result
for ordering in permutations(["A", "B", "C"]):
print("".join(ordering))
Open in the editor Download permutations.py
Output
ABC
ACB
BAC
BCA
CAB
CBA
How it works
Step through the program line by line: each step below shows up as its line runs.
-
resultcollects the finished orderings.currentis the ordering being built, andused[i]says whetheritems[i]is already in it. -
backtrackis a function insidepermutations, so it can use those three lists (scope). Whencurrentholds every item, it's a complete ordering: a copy goes intoresult, becausecurrentitself will keep changing. - Otherwise, each item that isn't used yet is tried in the next place: it's marked as used
and added to the end of
current. That's the choice. -
backtrack()calls itself to fill the places after it, finding every ordering that starts this way. - Back from that call, the choice is undone: the item comes off the end of
currentand is free again, so the loop can try the next item in the same place. - The first call starts with an empty ordering. When it returns, every ordering is in
result. - The program prints each ordering of A, B and C, joining its letters into one word.
How current grows and shrinks while the orderings that start with A are found:
| current | Then |
|---|---|
| (empty) | Choose A |
| A | Choose B |
| A B | Only C is free: choose it |
| A B C | Full: save ABC, undo C |
| A B | Nothing else is free: undo B |
| A | Choose C |
| A C | Only B is free: choose it |
| A C B | Full: save ACB, undo B |
| A C | Nothing else is free: undo C |
| A | Nothing else is free: undo A |
| (empty) | Choose B, and the same again |
Time and space complexity
| Time | O(n ร n!) |
|---|---|
| Extra space | O(n) |
There are n! orderings, and each one is copied into result in n steps, so the time is O(n ร n!). Factorials grow
fast: 3 items have 6 orderings, 10 items have 3,628,800, so listing every ordering only works for short lists. Besides
the result, the function keeps current and used, n items each, and the calls to backtrack go n deep, so the
extra space is O(n). The result itself holds n ร n! items: for 10 items, over 36 million.
Other ways to write it
With itertools.permutations()
The standard library makes the orderings for you, as tuples, in the same order. It's the one to use in real programs, and it can also pick orderings of only some of the items (modules).
from itertools import permutations
print(["".join(p) for p in permutations("ABC")])
pairs = list(permutations("ABCD", 2))
print(len(pairs), "ways to pick 2 of 4 in order")By swapping items in place
This version needs no used list: it swaps each item into the next place, explores, then swaps it back. The orderings
come out in a slightly different order: CBA before CAB.
def permute(items, start=0):
if start == len(items):
print("".join(items))
return
for i in range(start, len(items)):
items[start], items[i] = items[i], items[start] # choose
permute(items, start + 1) # explore
items[start], items[i] = items[i], items[start] # undo
permute(["A", "B", "C"])Try it yourself
- Add a fourth letter, and print
len()of the result to check there are 24 orderings. - Pass a word as a string, such as
permutations("CAT"): a string can be looped over like a list. - Try
["A", "A", "B"]: each ordering appears twice, as the function can't tell the two As apart. Keep one of each with a set of the joined words. - Save
currentonce it holds 2 items instead of all of them, to list the ways to pick 2 of the 3 letters in order.