LinQinの博客空间
首页项目归档照片墙音乐灵境说说杂谈友链关于
封面

LeetCode 面试经典150题

写作时间:2026-09-18 17:37:48

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

题解:

分组循环

适用场景:按照题目要求,数组会被分割成若干组,每一组的判断/处理逻辑是相同的。

核心思想:

外层循环负责遍历组之前的准备工作(记录开始位置),和遍历组之后的统计工作(更新答案)。

内层循环负责遍历组,找出这一组最远在哪结束。

这个写法的好处是,各个逻辑块分工明确,也不需要特判最后一组(易错点)。以我的经验,这个写法是所有写法中最不容易出 bug 的,推荐大家记住。

内层循环开始前

记录当前位置 start=i,这也是这一行第一个单词的下标。

初始化这一行的最小长度 sumLen 为 words[i] 的长度。

内层循环

从这一行的第二个单词 i+1 开始循环。

从第二个单词开始,每个单词之前必须有一个空格。

所以每个单词占用的长度是单词长度加一,加给 sumLen。

如果 sumLen+len(words[i])+1>maxWidth,退出循环。

内层循环结束后

这一行还剩下 extraSpaces=maxWidth−sumLen 个空格没有分配。

这一行单词之间的空隙个数 gaps=i−start−1,即单词个数减一。

首先处理特殊情况。如果只有一个单词,或者现在是最后一行,那么根据题目要求,所有单词左对齐,单词之间只有一个空格,末尾补上 extraSpaces 个空格。

然后处理一般情况。

单词之间至少有 ⌊

gaps

extraSpaces

​

⌋+1 个空格。其中 +1 是因为单词之间必须有一个空格,不算在 extraSpaces 中,这里重新加进来。

还剩下 rem=extraSpacesmodgaps 个空格,分配给前 rem 个空隙。换句话说,前 rem+1 个单词之间的空格个数多 1。

class Solution {
    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ans = new ArrayList<>();//存储答案不定长数组列表ArrayList
        int n = words.length; // length 是数组对象的属性,直接.length 获取而不用.length();
        for (int i = 0; i < n; ) { // 外层循环,用于记录内循环的行的开始位置,以及遍历后的统计,i由内层循环控制
            int start = i; // 这轮循环第一个单词的下标,第一次循环下标为0开始
            int sumLen  = words[i].length(); // 第i个单词的长度
            for (i++; i<n && sumLen + words[i].length() + 1 <= maxWidth;i++) { // i++ 因为第一个单词已经算进 `sumLen` 了,所以从**第二个单词word[2]**开始试探,如果长度加起来放得下就就更新 sumLen 并且更新i准备判断下一个单词word[3]能否放入
                sumLen += words[i].length() + 1;
            }

            int extraSpaces = maxWidth - sumLen; // 这一行剩余的可分配的空格数
            int gaps = i - start -1; // 这一行的空隙数(单词个数(i(现在在哪给单词) - start(这一行初始在哪个单词))减一)  如 i = 0; 初始一个单词,放入一个单词后 i 经过 ++i, i++,i变为2, 2-0 =2两个单词,1个间隔

            // 先处理特殊情况:如果只有一个单词,或者是最后一行,那么左对齐,末尾补空格
            if (gaps  ==  0 || i == n) { // gaps=0,只有一个单词,没有间隔,或者i为最后一个单词n了
                String row = join(words, start, i, " ") + " ".repeat(extraSpaces);
                ans.add(row);
                continue;
            }

            // 一般情况:把 extraSpaces 个空格均匀分配到 gaps 个空隙中(靠左的空格更多)
            int avg = extraSpaces / gaps;
            int rem = extraSpaces % gaps;
            String spaces = " ".repeat(avg + 1); // +1 表示加上单词之间已有的一个空格
            String row = join(words, start, start + rem + 1, spaces + ' ') + // 前 rem 个空隙多一个空格
                    spaces + join(words, start + rem + 1, i, spaces);
            ans.add(row);
        }
        return ans;
    }
    // 用 StringBuilder 的写法见【Java 写法二】
    private String join(String[] words, int start, int end, String sep) {
        return String.join(sep, Arrays.copyOfRange(words, start, end));
    }
}

复杂度分析

时间复杂度:O(nL+maxWidth),其中 n 是 words 的长度,L≤20 是 words[i] 的最大长度。虽然写了个二重循环,但是内层循环中对 i 加一的总执行次数不会超过 n 次,所以总的循环次数是 O(n) 的。最后一行需要 O(maxWidth) 的时间,其余行消耗的时间之和是 O(nL)。你可能会问,如果每一行都只有一个单词呢?这种情况下 2L+1>maxWidth,又由于 L≤maxWidth,所以 L 和 maxWidth 是同阶的,此时 O(nL)=O(n⋅maxWidth)。

空间复杂度:O(nL+maxWidth)。最后一行需要 O(maxWidth) 的空间,其余行消耗的空间之和是 O(nL)。

作者:灵茶山艾府

链接:https://leetcode.cn/problems/text-justification/solutions/535122/golang-jian-ji-xie-fa-by-endlesscheng-180a/

来源:力扣(LeetCode)

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

avatar

LinQin

内陆某双非院校软件工程专业本科生,方向为后端开发,互联网边缘地带人员。

RECOMMENDED

Hello

2026-03-24 07:00:45

LeetCode 面试经典150题

2026-09-14 16:57:12

LeetCode 面试经典150题

2026-09-17 11:51:03

Table of Contents