Problem Statement in English

You’re given an array of strings words and a width maxWidth. You need to format the text such that each line has exactly maxWidth characters and is fully (left and right) justified.

The last line should be left-justified, and no extra space is inserted between words.

Return the formatted text as an array of strings, where each string represents a line of text.


Approach

Since for each line the number of whitespaces between words can be calculated using the number of characters in the words and the number of words, we can iterate through the list of words and keep track of the number of characters and the number of words in the current line. When we reach a word that would make the line exceed maxWidth, we can assemble the line using the words we’ve collected so far, and then reset our counters for the next line.

Assembling the line involves calculating the number of spaces to insert between words. If it’s the last line or if there’s only one word in the line, we can simply left-justify the line by joining the words with a single space and adding any remaining spaces at the end. Otherwise, we calculate the number of spaces to distribute evenly between words, and if there are any extra spaces, we distribute them starting from the left.

Finally, we return the list of formatted lines.

And we’re done!


Solution in Python


class Solution:
    def fullJustify(self, words: list[str], maxWidth: int) -> list[str]:
        l = c_chars = c_word_count = 0
        res = []

        def assemble(r, lastLine):
            nonlocal l, c_word_count, c_chars

            if lastLine or c_word_count == 1:
                buffer = " ".join(words[l : r + 1])
                buffer += " " * (maxWidth - len(buffer))
                res.append(buffer)
                return

            gaps = maxWidth - c_chars
            gap = gaps // (c_word_count - 1)
            spare = gaps % (c_word_count - 1)

            buffer = ""
            for i in range(l, r):
                buffer += words[i]
                buffer += " " * gap
                if spare > 0:
                    buffer += " "
                    spare -= 1
            
            buffer += words[r]
            res.append(buffer)

        for i, word in enumerate(words):
            wordLen = len(word)

            if c_chars + c_word_count + wordLen > maxWidth:
                assemble(i - 1, False)
                c_chars = wordLen
                c_word_count = 1
                l = i
            else:
                c_chars += wordLen
                c_word_count += 1

        assemble(len(words) - 1, True)

        return res

Complexity

  • Time: $O(n)$
    Since we are iterating through the list of words once, the time complexity is linear with respect to the number of words.

  • Space: $O(n)$
    Since we are storing the result in a list, the space complexity is linear with respect to the number of words.


Mistakes I Made

I missed some edge cases.


And we are done.