【每日一题 2021-09-09】68. 文本左右对齐

2021-09-09   


题目

68. 文本左右对齐 (困难)

给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。

你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。

要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。

文本的最后一行应为左对齐,且单词之间不插入额外的空格。

说明:

  • 单词是指由非空格字符组成的字符序列。
  • 每个单词的长度大于 0,小于等于 maxWidth。
  • 输入单词数组 words 至少包含一个单词。

示例:

输入:
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
输出:
[
   "This    is    an",
   "example  of text",
   "justification.  "
]

示例 2:

输入:
words = ["What","must","be","acknowledgment","shall","be"]
maxWidth = 16
输出:
[
  "What   must   be",
  "acknowledgment  ",
  "shall be        "
]
解释: 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
     因为最后一行应为左对齐,而不是左右两端对齐。       
     第二行同样为左对齐,这是因为这行只包含一个单词。

示例 3:

输入:
words = ["Science","is","what","we","understand","well","enough","to","explain",
         "to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20
输出:
[
  "Science  is  what we",
  "understand      well",
  "enough to explain to",
  "a  computer.  Art is",
  "everything  else  we",
  "do                  "
]

题解

/*
 * 时间: 2021-09-09 22:53
 * 分析: 单词排版
 * 思考: 贪心策略分配每一行的单词
 */

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

class Solution {
    public List<String> fullJustify(String[] words, int maxWidth) {
        ArrayList<String> buf = new ArrayList<>();
        List<String> ans = new ArrayList<>();
        int bufLen = 0;

        for (String word : words) {
            int len = word.length();
            if (bufLen + len <= maxWidth) {
                buf.add(word);
                bufLen += len + 1;
            } else {
                ans.add(zipString(buf, bufLen, maxWidth));
                buf.clear();
                buf.add(word);
                bufLen = len + 1;
            }
        }

        // 处理最后一行
        StringBuilder sb = new StringBuilder();
        Iterator<String> iter = buf.iterator();
        while (iter.hasNext()) {
            String s = iter.next();
            if (!iter.hasNext()) {
                sb.append(s);
                break;
            }
            sb.append(s).append(" ");
        }
        if (sb.length() < maxWidth) {
            sb.append(getBlank(maxWidth - sb.length()));
        }
        ans.add(sb.toString());

        return ans;
    }

    private static String zipString(ArrayList<String> buf, int bufLen, int maxWidth) {
        StringBuilder sb = new StringBuilder();
        int wordCnt = buf.size();
        int charCnt = bufLen - wordCnt;
        int blankCnt = maxWidth - charCnt;

        if (wordCnt == 1) {
            return sb.append(buf.get(0)).append(getBlank(blankCnt)).toString();
        }

        int blankBufLen = blankCnt / (wordCnt - 1);
        int blankBufRemainCnt = blankCnt % (wordCnt - 1);

        int cnt = 0;
        Iterator<String> iter = buf.iterator();
        while (iter.hasNext()) {
            String s = iter.next();
            if (!iter.hasNext()) {
                sb.append(s);
                break;
            }

            if (cnt < blankBufRemainCnt) {
                sb.append(s).append(getBlank(blankBufLen + 1));
            } else {
                sb.append(s).append(getBlank(blankBufLen));
            }
            cnt++;
        }
        return sb.toString();
    }

    private static StringBuilder getBlank(int cnt) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < cnt; i++) {
            sb.append(" ");
        }
        return sb;
    }
}

Q.E.D.