Coding Interview Patterns Module 16 – Backtracking
Permutations and next permutation
List every permutation with used flags or swaps, skip repeated orderings, find the next permutation in place and build the k-th one from factorials.
What you will learn
- Generate every permutation of a list with used flags or with swaps
- Avoid repeated orderings when values repeat
- Compute the next permutation in place in O(n) time, and prove it is the very next one
- Build the k-th permutation directly from factorials, and its rank from an ordering
- Detect where 64-bit factorials stop in Java, C++ and Go
Before you start
What you’ll learn · Before you start
What you will learn
- Generate every permutation of a list with used flags or with swaps
- Avoid repeated orderings when values repeat
- Compute the next permutation in place in O(n) time, and prove it is the very next one
- Build the k-th permutation directly from factorials, and its rank from an ordering
- Detect where 64-bit factorials stop in Java, C++ and Go
Before you start
On this page
A permutation is one ordering of a list’s items, and n different items have n! permutations: 24 for four items, 3,628,800 for ten. Listing all permutations places the items one position at a time, as a backtracking search. The next permutation of an ordering is the one right after it in sorted order. It can be found in place, in O(n) time, without listing any others. Four tools cover the family. Used flags mark which items are already placed. Swaps keep the unplaced items inside the list itself. A skip rule stops equal values from being tried twice at one position. Dividing by factorials builds the k-th permutation directly.
Two problems about orderings
Problem A: every seating. Write seatings(guests, pair), which lists every order of the guests in a row of seats
in which the two guests of pair sit side by side. Limits: n ≤ 9. For guests A, B, C and D with the pair A and B,
12 of the 24 orders qualify, from ABCD to DCBA. A variant lists the distinct orderings of values that repeat. Their
number is n! divided by the orderings of each group of equal values: toffee has 6! / (2! × 2!) = 180.
Problem B: the next code. A display shows a code of n digits. Its next code is the smallest code larger than it that uses exactly the same digits; after the largest comes the smallest. Rearrange the digits in place, with O(1) extra memory. Limits: 1 ≤ n ≤ 10⁵.
- 534976 becomes 536479.
- 4321 becomes 1234: it was the largest.
- 1155 becomes 1515, with repeated digits.
The brute force, and why it fails
Try every ordering. For A, keep those where the pair sits together. For B, keep the smallest ordering above the code, which is its next permutation:
"""Both problems by brute force: try every ordering, then keep what the problem asks for."""
import math
import time
from itertools import permutations
def next_code_brute(code):
"""The smallest ordering of the digits that is larger than code; after the largest comes the smallest."""
current = tuple(code)
larger = (p for p in permutations(code) if p > current) # every ordering of the positions: n! of them
best = min(larger, default=None)
return "".join(best if best is not None else sorted(code))
def seatings_brute(guests, pair):
"""Every seating order in which the two guests of pair sit side by side."""
a, b = pair
return ["".join(p) for p in permutations(guests) if abs(p.index(a) - p.index(b)) == 1]
print(next_code_brute("534976"), next_code_brute("4321"), next_code_brute("1155"))
orders = seatings_brute("ABCD", ("A", "B"))
print(f"{len(orders)} of {math.factorial(4)} seating orders keep A and B together: {' '.join(orders)}")
print("digits orderings tried time")
for code in ["31415926", "314159265", "3141592653"]:
start = time.perf_counter()
next_code_brute(code)
seconds = time.perf_counter() - start
print(f"{len(code):>6} {math.factorial(len(code)):>16,} {seconds:.2f} s")
print(f"12 digits: {math.factorial(12):,} orderings; 20 digits: {math.factorial(20):,}") Output
536479 1234 1515
12 of 24 seating orders keep A and B together: ABCD ABDC BACD BADC CABD CBAD CDAB CDBA DABC DBAC DCAB DCBA
digits orderings tried time
8 40,320 0.00 s
9 362,880 0.17 s
10 3,628,800 1.72 s
12 digits: 479,001,600 orderings; 20 digits: 2,432,902,008,176,640,000
This output changes from run to run: the times depend on the computer and on what else it is doing
Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py
Runs on this device, in your browser. The first run downloads Python (about 13.5 MB), which is kept for the next runs.
Your run, in this browser
Each digit multiplies the work: 10 digits take seconds, 12 digits need 479,001,600 orderings and 20 digits need 2.4 × 10¹⁸. At 10⁵ digits the brute force cannot even start. For A it is acceptable, because the answer itself has tens of thousands of orderings at 9 guests, but it still builds every ordering before checking the pair.
What to notice
Reading 534976 from the right
Text description of the diagram
The diagram shows the six digits of the code 534976 in a row of boxes: 5, 3, 4, 9, 7 and 6. Read from the right, 7 is at least 6 and 9 is at least 7, so the last three digits, 9, 7 and 6, are shaded and marked with a bracket: from left to right they never increase. That is already the largest order of those three digits, so rearranging them alone cannot make the code larger.
The digit 4 before them has a bold outline. It is the first digit from the right that is smaller than the digit after it, 4 against 9, and a dashed line marks it as the place where the change to the next larger code must happen.
Read the code from the right. While the digits never increase, the suffix is already the largest order of its own digits, so rearranging it alone cannot give a larger code. The change must happen at the first digit, from the right, that is smaller than the digit after it. For A, a guest of the pair whose two neighbouring seats are taken by others can never sit by its partner, so that branch can stop at once.
Next permutation in four steps, with a dry run Pro: opens with a Pro, Premium or Ultimate pass
In this part:
- Why the four steps give the very next ordering, with a proof
- The code in five languages
- Checked against the brute force on 3,092 codes
- Listing every ordering: used flags or swaps
- Pruning the seating search, measured
- Repeated values: the skip rule for orderings
- The k-th ordering, directly from factorials
- Exercise: the k-th seating order
- The k-th seating order without listing the others
- Variants
- Edge cases and common bugs
- A practice set with answers
- Check yourself
- Interview questions
- How many orderings do n items have when they are all different, and how many distinct ones when some repeat?
- A booking system issues ticket codes as rearrangements of a fixed set of digits, each code the next larger one after the last. A teammate's function returns a larger rearrangement, but some codes are never issued. How do you compute the very next code in place, and how do you show that none is skipped?
- A seating planner must show the k-th seating of 20 guests in sorted order, for any k up to 20!, without listing the seatings before it. How do you compute it, which integer types hold k in Java, C++ and Go, and what changes at 21 guests?
- A word game must list every distinct arrangement of the letters of a 12-letter word with many repeated letters. Generating all orderings and removing repeats with a set takes minutes. Why, how do you list each distinct arrangement once, and how many are there for aabbccddeeff?
- Key takeaways
8 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 22 minutes
Opening this part with your pass…
This part opens with any MySmartCoPilot pass.
- Pro pass · 1 week₹79$2.99
- 30 days₹179$5.99
- 1 year₹1,699$45
One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.
Passes can’t be bought right now, so this part can’t be opened at the moment. The free part above stands on its own. If you have a pass, enter your licence key.
It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).
References
- itertools.permutations() (The Python Standard Library) (Python Software Foundation)
- math.factorial() and math.perm() (The Python Standard Library) (Python Software Foundation)
- NIST Dictionary of Algorithms and Data Structures: permutation (National Institute of Standards and Technology (NIST))
- std::next_permutation (cppreference.com) (cppreference.com)
- Java SE 25 API: Math.multiplyExact(long, int) (Oracle)
- Java SE 25 API: java.util.List (remove(int) and remove(Object)) (Oracle)
- Package math/bits: Mul64 (The Go Authors)
- Package slices: Reverse and Delete (The Go Authors)
Related tools
Report a problem with this lesson
Kept only in this browser. Your Learn progress