string-justification
text-alignment
algorithm
programming
text-formatting

Justify string algorithm

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

A full string-justification algorithm formats text so each line reaches a target width by distributing spaces between words. The tricky part is not splitting words into lines. It is deciding how to distribute the extra spaces when a line has more than one word. Once you separate line packing from space distribution, the algorithm becomes much easier to reason about.

Pack Words Greedily into Each Line

The usual first step is greedy packing: keep adding words to the current line until the next word would exceed the line width.

python
1def pack_lines(words, width):
2    lines = []
3    current = []
4    current_len = 0
5
6    for word in words:
7        if current and current_len + len(current) + len(word) > width:
8            lines.append(current)
9            current = []
10            current_len = 0
11        current.append(word)
12        current_len += len(word)
13
14    if current:
15        lines.append(current)
16    return lines

The len(current) term accounts for the minimum one-space gaps between already packed words.

Justify One Line at a Time

Once you know which words belong on a line, compute how many spaces are needed to fill the width.

python
1def justify_line(words, width, last_line=False):
2    if last_line or len(words) == 1:
3        line = " ".join(words)
4        return line + " " * (width - len(line))
5
6    total_chars = sum(len(word) for word in words)
7    total_spaces = width - total_chars
8    gaps = len(words) - 1
9    base, extra = divmod(total_spaces, gaps)
10
11    parts = []
12    for i, word in enumerate(words[:-1]):
13        spaces = base + (1 if i < extra else 0)
14        parts.append(word + " " * spaces)
15    parts.append(words[-1])
16    return "".join(parts)

This is the core of full justification: distribute the remainder spaces from left to right after giving each gap its base share.

Put the Whole Algorithm Together

The full solution combines greedy line packing with line-specific formatting.

python
1def full_justify(words, width):
2    packed = pack_lines(words, width)
3    result = []
4
5    for i, line_words in enumerate(packed):
6        result.append(justify_line(line_words, width, last_line=(i == len(packed) - 1)))
7
8    return result
9
10text = ["This", "is", "a", "simple", "text", "justification", "example."]
11for line in full_justify(text, 16):
12    print(repr(line))

The last line is usually left-justified rather than fully justified. That is a formatting rule, not an algorithmic necessity, but it is part of the standard version of the problem.

Why the Leftmost Gaps Get the Extra Spaces

When the space count does not divide evenly, typical text-justification rules place the larger gaps earlier in the line. That keeps the result deterministic and avoids ugly ambiguity in the output.

This detail matters because many incorrect solutions distribute spaces inconsistently or only approximately, which makes them fail exact-output tests.

Think About Edge Cases Early

Single-word lines, the last line, empty input, and words longer than the target width all need explicit decisions. Most challenge versions assume no single word exceeds the maximum width, but real text formatting code may need hyphenation or overflow rules too.

That is why justification algorithms are often simpler in coding interviews than in full text-layout engines.

Another useful check is deterministic output. If the same input can produce different spacing patterns depending on loop order or leftover arithmetic, exact-output tests will fail even when the line widths look visually correct.

Common Pitfalls

  • Mixing line packing and space distribution into one hard-to-debug loop.
  • Forgetting that the last line is usually left-justified.
  • Handling uneven space distribution inconsistently.
  • Failing on single-word lines.
  • Ignoring assumptions about words that are longer than the line width.

Summary

  • String justification has two main steps: pack words into lines, then distribute spaces.
  • Greedy packing is the standard strategy for choosing which words go on each line.
  • Full justification distributes extra spaces as evenly as possible across gaps.
  • The last line is usually left-justified.
  • Correct handling of edge cases is what separates a clean solution from a fragile one.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.