【LeetCode】每日一题 文本左右对齐

236 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第32天,点击查看活动详情

68. 文本左右对齐

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

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

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

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

注意:

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

「示例1:」
输入: 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                  "]

「提示:」

1 <= words.length <= 300
1 <= words[i].length <= 20
words[i] 由小写英文字母和符号组成
1 <= maxWidth <= 100
words[i].length <= maxWidth

解题思路

对齐规则:
​
最后一行
单词左对齐
单词间空格数为一
非最后一行
单词左右对齐
单词间空格均匀分布
无法均匀分布时, 左侧空格数多于右侧空格数.
递归的最小重复单元(形成输出数组 res 的一个字符串)
​
Recursion terminatior (递归终止)
​
递归遍历到数组 words 的末尾
Process logic in current level (当前层的过程逻辑)
​
非最后一行
确定 words 中能加入该行字符串的个数, 并将字符串保存到数组 rowArr .
对数组 rowArr 进行"处理", 形成符合非最后一行规则的字符串, 保存到数组 res .
最后一行
确定 words 中能加入该行字符串的个数, 并将字符串保存到数组 rowArr .
对数组 rowArr 进行"处理", 形成符合最后一行规则的字符串, 保存到数组 res .
Drill down (去下一层)
​
return appendLine(words, maxWidth, res, i)
i: 对应下一次递归, 加入数组 rowArr 的首个字符串, 在数组 words 中的下标.
res: 要输出的数组
Reverse the current level status if needed (进行下一层的操作之后, 会回到这里. 可以在这里做一些收尾的工作.)
​
res.pop()
删去数组数组 res 最后一个数组. 这样在递归结束时, 数组 res 可以清空.

代码实现

/**
 * @param {string[]} words
 * @param {number} maxWidth
 * @return {string []}
 */
var fullJustify = function(words, maxWidth) {
    const appendLine = (level, words, maxWidth, res, start) => {
        // Recursion terminatior (递归终止)
        if (start >= words.length) {
            return res;
        }
        
        // Process logic in current level (当前层的过程逻辑)
        let rowArr = [words[start]];
        let count = words[start].length;
        let i = start + 1;
        while (i < words.length && count + words[i].length < maxWidth) {
            count += words[i].length + 1;
            rowArr.push(words[i]);
            i ++;
        }
        let rowStr = '';
        if (i < words.length) {
            let space = maxWidth - count + rowArr.length - 1;
            let eachSpace = parseInt(space / (rowArr.length - 1));
            let extSpace = space % (rowArr.length - 1);
            for (let j = 0; j < rowArr.length; j ++) {
                rowStr += rowArr[j];
                if (j !== rowArr.length - 1) {
                    let space = eachSpace;
                    if (extSpace > 0) {
                        space += 1;
                        extSpace --;;
                    }
                    while (space -- > 0) {
                        rowStr += ' ';
                    }
                }
            }
        } else {
            for (let j = 0; j < rowArr.length; j ++) {
                if (j < rowArr.length - 1) {
                    rowStr += rowArr[j] + ' ';
                } else {
                    rowStr += rowArr[j];
                }
            }
        }
        while (rowStr.length < maxWidth) {
            rowStr += ' ';
        }
        res.push(rowStr);
        
        // Drill down (去下一层)
        return appendLine(level + 1, words, maxWidth, res, i);
        
        // Reverse the current level status if needed (进行下一层的操作之后, 会回到这里. 可以在这里做一些收尾的工作.)
        res.pop();
    }
    return appendLine(0, words, maxWidth, [], 0);
};

如果你对这道题目还有疑问的话,可以在评论区进行留言;

\