leetcode68- Text Justification- hard

Given an array of words and a length L, format the text such that each line has exactly L 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 L characters.

Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do 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.

For example,
words: ["This", "is", "an", "example", "of", "text", "justification."]
L: 16.

Return the formatted lines as:

[
   "This    is    an",
   "example  of text",
   "justification.  "
]

Note: Each word is guaranteed not to exceed L in length.

算法:直接上,细节多。步骤如下:

1. 找到当前行需要加的单词。(最后用idx指最后一个有效单词的下标,wordsC来计数要取多少个,wordsL记着单词长度为2做准备)

2. 算出需要加的extra space (maxWidth - (wordsL + wordsC - 1)),还要分解为even的和uneven的,用/ %做。

3. 创造当前行

细节:

1. 添加某个个数个空格经常用,可以写个小函数。 2.创造行的时候每加一个单词后面都要还加一个空格,因为这是你计算空格的前提。 3.每行最后一个单词也很特殊。正常情况下最后个单词后面都不加空格了,但如果这行就只有这一个单词那又要加空格填满,处理。 4.加最后一行也处理比较独特,可以直接拉一个小函数出来。5.因为每一行你做的时候定义idx放在最后一个有效单词的下标,那你这一轮结束后要记得idx++,从而让下一轮开始的时候idx放在的是新的可加单词上面了。 6.计算单词长度和的时候加的是words[i].length()不是单单words[i],你写的时候老写错,小心。

class Solution {
    // general approach:
    // 1. find appropriate words.
    // 2. count how many addition spaces needed (L - (wordsL + wordsC - 1))
    // 3. assign spaces
    // detail:
    // 1. the last line
    
    
    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> result = new ArrayList<>();
        if (words == null || maxWidth < 0 ) {
            return result;
        }
        
        int idx = 0;
        while (idx < words.length) {
            // 1. find appropriate words
            // 这里老是写错,记录的是string长度,记得调用.length()
            int wordsL = words[idx].length();
            int wordsC = 1;
            while (wordsL + wordsC - 1 <= maxWidth) {
                // TODO add the last line
                if (idx + 1 >= words.length) {
                    addLastLine(words, maxWidth, idx - wordsC + 1, result);
                    return result;
                }
                idx++;
                wordsL += words[idx].length();
                wordsC ++;
            }
            wordsC--;
            wordsL -= words[idx].length();
            idx --;
            
            // 2.count how many extra spaces needed        
            int spaceX = maxWidth - (wordsL + wordsC - 1);
            int spaceEven = wordsC == 1 ? spaceX : spaceX / (wordsC - 1);
            int spaceUneven = wordsC == 1 ? 0 : spaceX % (wordsC - 1);
            
            // 3.assign spaces
            StringBuilder sb = new StringBuilder();
            for (int i = idx - wordsC + 1; i < idx; i++) {
                sb.append(words[i]);
                // 这里要加一个,本来你的计算方式里就是有算了每个空格后面的
                sb.append(" ");
                appendSpace(sb, spaceEven);
                if (i - (idx - wordsC + 1) < spaceUneven) {
                    sb.append(" ");
                }
            }
            // 细节,最后一个单词后面不加空格,拉出来
            sb.append(words[idx]);
            // 细节,如果只有一个单词,后面还要加上去空格
            if (wordsC == 1) {
                appendSpace(sb, spaceEven);
            }
            result.add(sb.toString());
            // 记得你定义的idx是最后一个字符的下标,所以结束这轮后要+1,否则死循环。
            idx++;
        }
        
        return result;
    }
    
    private void addLastLine(String[] words, int maxWidth, int idx, List<String> result) {
        StringBuilder sb = new StringBuilder();
        int cnt = 0;
        for (int i = idx; i < words.length - 1; i++) {
            sb.append(words[i]);
            sb.append(" ");
            cnt += (words[i].length() + 1);
        }
        sb.append(words[words.length - 1]);
        cnt += words[words.length - 1].length();
        appendSpace(sb, maxWidth - cnt);
        result.add(sb.toString());
    }
    
    private void appendSpace(StringBuilder sb, int cnt) {
        for (int i = 0; i < cnt; i++) {
            sb.append(" ");
        }
    }
}