68. Text Justification

https://leetcode.com/problems/text-justification/description/

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. If the number of spaces on a line does not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right. For the last line of text, it should be left-justified, and no extra space is inserted between words. Note:

A word is defined as a character sequence consisting of non-space characters only. 	
Each word's length is guaranteed to be greater than 0 and not exceed maxWidth. 	
The input array words contains at least one word. 

Example 1: Input: words = [“This”, “is”, “an”, “example”, “of”, “text”, “justification."], maxWidth = 16 Output: [ “This is an”, “example of text”, “justification. " ] Example 2: Input: words = [“What”,“must”,“be”,“acknowledgment”,“shall”,“be”], maxWidth = 16 Output: [ “What must be”, “acknowledgment “, “shall be " ] Explanation: Note that the last line is “shall be " instead of “shall be”, because the last line must be left-justified instead of fully-justified. Note that the second line is also left-justified because it contains only one word. Example 3: Input: words = [“Science”,“is”,“what”,“we”,“understand”,“well”,“enough”,“to”,“explain”,“to”,“a”,“computer.”,“Art”,“is”,“everything”,“else”,“we”,“do”], maxWidth = 20 Output: [ “Science is what we”, “understand well”, “enough to explain to”, “a computer. Art is”, “everything else we”, “do " ]

Constraints:

1 <= words.length <= 300 	
1 <= words[i].length <= 20 	
words[i] consists of only English letters and symbols. 	
1 <= maxWidth <= 100 	
words[i].length <= maxWidth

  • code
class Solution {
    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> res = new ArrayList<>();
        int index = 0;
        while (index < words.length) {
            int len = words[index].length();
            int last = index + 1;
            while (last < words.length) {
                if (words[last].length() + len + 1 > maxWidth) break;
                len += 1 + words[last].length();
                last++;
            }
            // valid index range is: [index, last - 1]

            StringBuilder sb = new StringBuilder();

            sb.append(words[index]);
            // how many space slots on the current line
            int spaces = last - 1 - index;
            // for last line, always left-justified
            // or if there is only one words
            if (last == words.length || spaces == 0) {
                for (int i = index + 1; i < last; i++) {
                    sb.append(" ");
                    sb.append(words[i]);
                }
                for (int i = sb.length(); i < maxWidth; i++) {
                    sb.append(" ");
                }
            } else {
                // split the remaining slots to number of spaces
                int extra = (maxWidth - len) / spaces;
                // for the remaining mod value, assign to first empty slots
                int remain = (maxWidth - len) % spaces;
                for (int i = index + 1; i < last; i++) {
                    for (int k = extra; k > 0; k--) {
                        sb.append(" ");
                    }
                    if (remain-- > 0) {
                        sb.append(" ");
                    }
                    sb.append(" ");
                    sb.append(words[i]);
                }
            }
            res.add(sb.toString());
            index = last;
        }
        return res;
    }
}
  • code
class Solution {

    public String divide(List<String> eachRow, int maxWidth){
        int spaces = maxWidth - eachRow.stream().mapToInt(i -> i.length()).sum();
        int interval = eachRow.size() - 1;

        if (interval == 0){
            StringBuilder res = new StringBuilder();
            res.append(eachRow.get(0)).append(" ".repeat(maxWidth - eachRow.get(0).length()));
            return res.toString();
        } 
            
        if (interval != 0 && spaces % interval == 0){
            int eachspace = spaces / interval;
            return String.join(" ".repeat(eachspace), eachRow);
        }else{
            int eachspaceR = spaces / interval;
            int eachspaceL = eachspaceR + 1;
            int numL = spaces - eachspaceR * interval;
            int numR = interval - numL;

            StringBuilder res = new StringBuilder();
            int i = 0;
            while (numL > 0){
                res.append(eachRow.get(i)).append(" ".repeat(eachspaceL));
                i++;
                numL--;
            }
            while (numR > 0){
                res.append(eachRow.get(i)).append(" ".repeat(eachspaceR));
                i++;
                numR--;
            }
            res.append(eachRow.get(i)); // last word
            return res.toString();
        }
    }

    // left-justified, and no extra space is inserted between words.
    public String divideLastRow(List<String> eachRow, int maxWidth){
        String res = String.join(" ", eachRow);
        return res + " ".repeat(maxWidth - res.length());
    }

    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> curRow = new ArrayList<>();
        List<String> res = new ArrayList<>();
        int curRowUsed = 0;
        int i = 0; // word index, when i == words.length() - 1, last row
  
        while (i < words.length){
            // first word in each row
            if (curRowUsed == 0){
                curRow.add(words[i]);
                curRowUsed += words[i].length();
                // this word is in the last 
                if (i == words.length - 1){
                    res.add(divideLastRow(curRow, maxWidth));
                }
                i++;
                continue;
            }
            
            // add one more word to current row
            if (curRowUsed + 1 + words[i].length() <= maxWidth){
                curRowUsed += (1 + words[i].length());
                curRow.add(words[i]);
                if (i == words.length - 1){
                    res.add(divideLastRow(curRow, maxWidth));
                }
                i++;
            // beyond current row, so not last row yet
            }else{
                res.add(divide(curRow, maxWidth));
                curRowUsed = 0;
                curRow.clear();
            }
        }

        return res;
    }
}