力扣第六十八题-文本左右对齐

296 阅读3分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

前言

力扣第六十八题 文本左右对齐 如下所示:

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

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

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

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

示例:

image.png

一、思路

题目中有一个比较容易忽略的点单个单词一组和最后一行的都为左对齐,单词间没有额外的空格,其他的方面就是根据题目的要求来进行逻辑模拟了。

大致的步骤分为以下几步:

  1. 先将所有的单词分组
  2. 按照题目要求,每一组都按照要求补充单词间的空格(单个单词和最后一行特殊处理左对齐)

举个例子

此处以示例一作为例子

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

maxWidth = 16

  1. words 经过分组后,分为了三个组。分别为 ["This", "is", "an"]["example", "of", "text"]["justification."]
  2. 第一组和第二组均匀分配空格的数量,结果分别为 "This    is    an""example  of text"
  3. 第三组靠左对齐,并在后面补上空格即可。结果为 "justification.  "
  4. 返回处理后的结果即可

二、实现

实现代码与思路中保持一致,使用了 List<List<String>> group 来存储分组的结果,代码如下所示:

实现代码

    public List<String> fullJustify(String[] words, int maxWidth) {
        List<String> ret = new ArrayList<>();
        // 分组结果
        List<List<String>> group = new ArrayList<>();
        // 1. 分组
        for (int i=0; i<words.length; i++) {
            List<String> temp = new ArrayList<>();
            int rowLen = words[i].length();
            temp.add(words[i]);
            while (i < words.length -1 && rowLen + 1 + words[i+1].length() <= maxWidth) {
                temp.add(words[i+1]);
                rowLen += 1 + words[i+1].length();
                i++;
            }
            group.add(temp);
        }
        // 2. 根据分组结果
        for (int i=0; i<group.size(); i++) {
            List<String> temp = group.get(i);
            if (i == group.size() -1) {  // 最后一行
                StringBuilder sb = new StringBuilder(temp.get(0));
                for (int k = 1; k < temp.size(); k++) {
                    sb.append(" ").append(temp.get(k));
                }
                while (sb.length() < maxWidth) sb.append(" ");
                ret.add(sb.toString());
            } else if (temp.size() == 1) {  // 单个单词
                String str = temp.get(0);
                while (str.length() != maxWidth) str += " ";
                ret.add(str);
                continue;
            } else {    // 普通情况,中间插空格
                // 求单词长度
                int wordWidth = 0;
                for (String str : temp) {
                    wordWidth += str.length();
                }
                int spaceWidth = maxWidth - wordWidth;
                int spaceItemWidth = spaceWidth / (temp.size() - 1);
                String spaceItem = "";
                for (int k = 0; k < spaceItemWidth; k++) spaceItem += " ";
                StringBuilder sb = new StringBuilder();
                for (int k = 0, sum = 0; k < temp.size(); k++) {
                    String item = temp.get(k);
                    sb.append(item);
                    if (k == temp.size() - 1) break;
                    sb.append(spaceItem);
                    sum += spaceItemWidth;
                    // 剩余的间隙数量(可填入空格的次数)
                    int remain = temp.size() - k - 1 - 1;
                    // 剩余间隙数量 * 最小单位空格长度 + 当前空格长度 < 单词总长度,则在当前间隙多补充一个空格
                    if (remain * spaceItemWidth + sum < spaceWidth) {
                        sb.append(" ");
                        sum++;
                    }
                }
                ret.add(sb.toString());
            }
        }
        return ret;
    }

测试代码

    public static void main(String[] args) {
        String[] strings = {"Science","is","what","we","understand","well","enough","to","explain","to","a","computer.","Art","is","everything","else","we","do"};
        new Number68().fullJustify(strings, 20);
    }

结果

image.png

三、总结

感谢看到最后,非常荣幸能够帮助到你~♥

如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~