Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 28 – String patterns

Text justification and word wrap

Fit words into lines of an exact width and spread the spaces evenly: the problem, worked examples, a brute force that tries every layout, and what to notice.

  • Intermediate
  • 30 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 8 of 30 minutes free
Free: The problem · The brute force: try every layout. With a pass: the other 11 sections and 3 interview answers, about 22 minutes.

What you will learn

  • Build lines greedily from words for a given width, and prove that greedy packing uses the fewest lines
  • Split the spaces of a line among its gaps from left to right with one division and its remainder
  • Handle the last line, one-word lines and words longer than the width as stated rules
  • Measure a line in display columns when the text holds wide characters or combining marks
  • Compare greedy wrapping with the most even wrapping found by dynamic programming

Before you start

What you’ll learn · Before you start

What you will learn

  • Build lines greedily from words for a given width, and prove that greedy packing uses the fewest lines
  • Split the spaces of a line among its gaps from left to right with one division and its remainder
  • Handle the last line, one-word lines and words longer than the width as stated rules
  • Measure a line in display columns when the text holds wide characters or combining marks
  • Compare greedy wrapping with the most even wrapping found by dynamic programming

Before you start

On this page

Text justification lays out words in lines of exactly the same width by widening the spaces between them, so that both margins are straight. Word wrap is the simpler half of the job: it breaks text into lines no wider than the width and leaves the right margin ragged. The usual method packs as many words as fit into each line, then shares a line’s spare spaces among its gaps with one division, the leftmost gaps taking any remainder. The rules that trip people up are the edges: the last line, a line with a single word, and a word that is wider than the line.

The problem

The problem

A school’s notice board shows announcements in a monospace font, width characters to a line. Write justify(words, width), which lays the words out in the fewest lines possible and returns them, each exactly width characters long. In every line but the last, the gaps between words are widened as evenly as possible, any extra spaces going to the leftmost gaps. A line with one word, and the last line, keep single spaces and are padded with spaces on the right. Every word is at most width characters long. Limits: 1 ≤ width ≤ 100, and up to 10⁴ words.

Two examples, with each line between bars:

  1. "Exam results will be posted on the notice board on Friday." at width 16 gives four lines: |Exam results|, |will be posted|, |on the notice| and |board on Friday.|.
  2. "Library closed for stock taking" at width 12 gives |Library |, a line with one word padded on the right, then |closed for| and |stock taking|.

Word wrap of the first notice gives the same four lines without the extra spaces: Exam results, will be posted, on the notice and board on Friday..

The line on the notice justified to 16 characters: 11 letters, 5 spaces in 2 gaps, 3 in the first gap and 2 in the second.on the notice, width 16The arithmeticon2␣␣␣3the3␣␣2notice6letters: 2 + 3 + 6 = 11spaces: 16 − 11 = 5, gaps: 25 = 2 × 2 + 1: the first gap gets the extra

One line of the notice, its letters and its gaps

Text description of the diagram

The diagram has two rows, one under the other.

  1. The line is drawn as five cells from left to right: the word on, 2 letters; a gap of 3 spaces; the word the, 3 letters; a gap of 2 spaces; and the word notice, 6 letters. The words have double borders and the gaps dashed borders.
  2. Three lines give the arithmetic. The letters add up to 2 + 3 + 6 = 11. The line must be 16 characters wide, so 16 − 11 = 5 spaces go into its 2 gaps. Dividing 5 by 2 gives 2 with a remainder of 1, so every gap gets 2 spaces and the first gap gets 1 more: 3 and 2.

The brute force: try every layout

The fewest lines can be found by trying every layout: a line may end after any of the n − 1 gaps between words, so there are 2ⁿ⁻¹ layouts, and the shortest one whose lines all fit wins. The run counts them:

Every layout tried, for notices of 11 to 16 words Python · brute/every_layout.py
# The fewest lines by brute force: try every way to break the words into lines, and keep the shortest valid layout.

def every_layout(words, width):
    """(fewest lines of a valid layout, layouts tried): a layout breaks after any subset of the n - 1 gaps."""
    n = len(words)
    best, tried = None, 0
    for breaks in range(2 ** (n - 1)):
        tried += 1
        lines, current = 0, [words[0]]
        ok = True
        for k in range(1, n):
            if breaks >> (k - 1) & 1:  # a line ends before word k
                ok = ok and len(" ".join(current)) <= width
                lines, current = lines + 1, [words[k]]
            else:
                current.append(words[k])
        ok = ok and len(" ".join(current)) <= width
        if ok and (best is None or lines + 1 < best):
            best = lines + 1
    return best, tried


notice = "Exam results will be posted on the notice board on Friday.".split()
fewest, tried = every_layout(notice, 16)
print(f"{len(notice)} words, width 16: fewest lines {fewest}, {tried:,} layouts tried")

longer = (notice + "Parents may collect the printed sheets at the office".split())
for n in (12, 14, 16):
    fewest, tried = every_layout(longer[:n], 16)
    print(f"{n} words: fewest lines {fewest}, {tried:,} layouts tried")

Output

11 words, width 16: fewest lines 4, 1,024 layouts tried
12 words: fewest lines 5, 2,048 layouts tried
14 words: fewest lines 6, 8,192 layouts tried
16 words: fewest lines 7, 32,768 layouts tried

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 every_layout.py

Every extra word doubles the count. The 11-word notice needs 1,024 layouts, 16 words need 32,768, and 10⁴ words would need 2⁹⁹⁹⁹, a number with 3,010 digits.

What to notice

A line that can take one more word gains nothing by refusing it: pushing a word to the next line can only push the following lines later. So packing each line as full as it can be gives the fewest lines without trying any other layout. After that, a line’s spaces are simply the width minus its letters, and one division with remainder shares them among its gaps. Text justification is that packing plus the division, and word wrap is the packing alone.

Greedy packing, and why it uses the fewest lines Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • The proof that no layout uses fewer lines
  • Spreading the spaces with one division
    • The last line, one-word lines and words that are too long
  • The code in five languages
  • Word wrap, next to Python’s textwrap
  • Width is not len() on a real notice board
  • The most even layout, by dynamic programming
  • Five bugs reproduced against the correct version
  • Exercise: justify a notice
    • Justify a notice to an exact width
  • A practice set with sample answers
  • Check yourself
  • Interview questions
    • A justified line holds four words with 13 letters in all and must be 24 characters wide. How many spaces go in each gap, which gaps get the extra ones, and how do you compute it without a loop? Which lines must not be justified, and why?
    • Prove that putting as many words as fit on each line gives the fewest lines possible. Then explain why the same rule can leave a very uneven right margin, and what you would use when an even margin matters.
    • A justifier that works on English notices misaligns lines on a monospace screen for notices in Japanese and for names with accents. Explain why with an example, and change the width measurement so that every line is exactly as wide as the board.
  • Key takeaways

7 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 19 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.

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

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.