95. Text Justification
hardAsked at SalesforceFormat text such that each line has exactly maxWidth characters with full justification. Salesforce uses this as a string-manipulation stress test.
By Sam K., Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Salesforce loops.
- Glassdoor (2026-Q1)— Salesforce uses text formatting in their email template rendering.
- Blind (2025)— Hard string-manipulation onsite question.
Problem
Given an array of strings words and a width maxWidth, format the text such that each line has exactly maxWidth characters and is fully (left and right) justified. You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly maxWidth characters. Extra spaces between words should be distributed as evenly as possible. The last line of text should be left-justified, and no extra space is inserted between words.
Constraints
1 <= words.length <= 3001 <= words[i].length <= 20words[i] consists of only English letters and symbols.1 <= maxWidth <= 100words[i].length <= maxWidth
Examples
Example 1
words = ["This", "is", "an", "example", "of", "text", "justification."], maxWidth = 16["This is an","example of text","justification. "]Approaches
1. Two-pass: select then format
First pass: group words into lines. Second pass: format each line.
- Time
- O(n)
- Space
- O(n)
function fullJustify(words, maxWidth) {
const result = [];
let i = 0;
while (i < words.length) {
let lineLen = words[i].length, j = i + 1;
while (j < words.length && lineLen + 1 + words[j].length <= maxWidth) {
lineLen += 1 + words[j].length;
j++;
}
const lineWords = words.slice(i, j);
const gaps = lineWords.length - 1;
let line;
if (gaps === 0 || j === words.length) {
line = lineWords.join(' ') + ' '.repeat(maxWidth - lineLen);
} else {
const totalSpaces = maxWidth - lineWords.reduce((s, w) => s + w.length, 0);
const base = Math.floor(totalSpaces / gaps), extra = totalSpaces % gaps;
line = lineWords.reduce((acc, w, idx) => {
if (idx === 0) return w;
return acc + ' '.repeat(base + (idx <= extra ? 1 : 0)) + w;
}, '');
}
result.push(line);
i = j;
}
return result;
}Tradeoff: Greedy line-packing + per-line distribution. Salesforce wants both passes done cleanly.
2. Single pass with running buffer
Process word by word; emit when adding next would overflow.
- Time
- O(n)
- Space
- O(n)
// Similar shape. Mostly identical to two-pass.Tradeoff: No advantage over two-pass.
Salesforce-specific tips
Salesforce uses text justification in email-template rendering and dashboard display. They grade on three things: (1) greedy line-packing logic, (2) extra-space distribution among gaps (extra spaces go to leftmost gaps first), (3) last-line special case (left-justified, no inter-word padding). Bonus signal: walk through the case where a line has only one word — must left-justify and pad with trailing spaces.
Common mistakes
- Forgetting the last-line special case — must be left-justified.
- Distributing extra spaces randomly instead of leftmost-first.
- Off-by-one on lineLen accumulation (+1 for the space).
Follow-up questions
An interviewer at Salesforce may pivot to one of these next:
- Optimal line-breaking with cost function (Knuth's algorithm).
- Soft-wrap a large block of text into a fixed width.
- Render markdown into fixed-width text.
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Why are extra spaces distributed leftmost-first?
Convention — leftmost gaps get rounded-up shares. So if there are 7 spaces over 3 gaps, the first gap gets 3, the second and third get 2 each.
What if a single word equals maxWidth?
It fills the line by itself, no spaces needed. Edge case worth confirming with the interviewer.