力扣68(java)-文本左右对齐(困难)

题目:

给定一个单词数组 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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/text-justification
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

属实打脑壳,数学思维,就是处理代码的时候转不过来弯,看了别人的代码,加上自己的注解

每一行的情况分为三种:

1.一行只有一个单词:先放入单词,计算出剩余的空格数,右边全部添加空格即可;

2.最后一行:除了每个单词后面的一个空格,不再添加额外空格,计算出额外的空格数,添加至末尾即可;

3.普通情况一行多词:先均匀分配空格数,不能均匀分配剩下的,从左边开始空格依次加1。

先写主框架,框架里面添加使用的方法名,然后遇到一个方法补充一个方法,在方法里面写上具体的处理逻辑,再回到主框架在方法名中添加具体的参数。

代码:

  1 class Solution {
  2     public List<String> fullJustify(String[] words, int maxWidth) {
  3         List<String> res = new ArrayList<>();
  4         //统计每行单词的长度
  5         int count = 0;
  6         //开始单词的位置
  7         int start = 0;
  8 
  9         for(int i = 0; i < words.length; i++){
 10             //单词的长度
 11             count += words[i].length();
 12             //如果当前单词的长度大于最大长度
 13             if(count > maxWidth){
 14                 //向结果中添加,只添加当前单词的前一个单词,不然没法加空格
 15                 res.add(fillword(words, start, i-1, maxWidth));
 16                 //更新起始位置
 17                 start = i;
 18                 //统计单词的长度从当前位置开始
 19                 count = words[i].length();
 20             }
 21             //遍历完每个单词时需要加上一个固定空格
 22             count++;
 23         }
 24         //处理剩下的单词
 25         res.add(fillword(words, start, words.length - 1, maxWidth));
 26         return res;
 27     }
 28 
 29     //每一行处理过程,分三种情况
 30     //start单词开始位置,end结束位置
 31     public String fillword(String[] words, int start, int end, int maxWidth) {
 32         StringBuilder sb = new StringBuilder();
 33         //当前行只有一个单词,不是最后一行
 34         if(start == end){
 35             oneWordfill(words, start, maxWidth, sb);
 36         }else if(end == words.length-1){
 37         //最后一行
 38             lastRowfill(words, start, end, maxWidth, sb);
 39         }else{
 40         //普通情况,一行多个单词
 41             normalfill(words, start ,end, maxWidth, sb);
 42         }
 43         return sb.toString();
 44     }
 45 
 46     //处理一行只有一个单词的方法
 47     public void oneWordfill(String[] words, int start, int maxWidth, StringBuilder sb){
 48         //添加单词到开头
 49         sb.append(words[start]);
 50         //该行剩下的其他位置添加空格
 51         int spacenums = maxWidth - words[start].length();
 52         for(int i = 0; i < spacenums; i++){
 53             sb.append(" ");
 54         }
 55     }
 56 
 57     //处理最后一行的方法
 58     public void lastRowfill(String[] words, int start, int end, int maxWidth, StringBuilder sb){
 59         for(int i = start; i <= end; i++){
 60             sb.append(words[i]);
 61             //还没打末尾时单词之间添加一个空格
 62             if(i != end){
 63                 sb.append(" ");
 64             } else{
 65             //单词添加完后,剩下的位置全为空格
 66             //统计空格数,并添加空格到末尾
 67                 int spacenums = maxWidth - sb.length();
 68                 for(int j = 0; j < spacenums; j++){
 69                 sb.append(" ");
 70                 }
 71             }
 72         }
 73     }
 74     
 75     //处理一般情况,平均分配空格,不能平均左边空格多于右边
 76     public void normalfill(String[] words, int start, int end, int maxWidth, StringBuilder sb){
 77         //先统计这行单词长度
 78         int wordslength = 0;
 79         for(int i = start; i <= end; i++){
 80             wordslength += words[i].length();
 81         }
 82         //统计均分的空格数,end-start为总的间隔数
 83         //比如从第三个单词开始,到第6个单词之间有三个间隔可以放空格
 84         int spaceavg = (maxWidth - wordslength) / (end - start);
 85         //不能均分之后的空格数
 86         //4个单词有3个间隔,一共有5个空格,均分一个空格之后,还留2个,结果就是第一个和第二个间隔后面两个空格,剩下的空隙一个空格
 87         int remainspace = (maxWidth - wordslength) % (end - start);
 88 
 89         for(int i = start; i <= end; i++){
 90             //添加单词进去
 91             sb.append(words[i]);
 92             if(i != end){
 93                 //添加平均分配的空格
 94                 for(int j = 0; j < spaceavg; j++){
 95                     sb.append(" ");
 96                 }
 97                 //添加剩余空格
 98                 if(remainspace > 0){
 99                     sb.append(" ");
100                     remainspace--;
101                 }
102             }
103         }
104     }
105 }

 记录一下我自己的疑惑点:

 

 我以为在当前单词后面添加空格会直到if语句不成立才会停止,这样就会添加多余空格。实际不是!!!

比如我理解的是:

4个单词有3个间隔,第一个单词后3个空格,第二个单词后2个,第三个单词后1个,但是实际是第一个单词后面2个空格,第一个单词后面2个空格,第三个单词后面1个空格。
正确执行过程:
先添加第一个单词,然后添加平均分配的空格1个,执行下一个if语句,添加一个多余空格,执行完后,remainspace=1,就继续添加第二个单词,添加平均分配的空格1个,在执行if语句,添加一个多余的空格,执行完后remainspace由1变为0,再添加第三个单词,添加平均分配的空格1个,由于remainspace = 0 没法执行if语句,不再添加多余空格了,再继续添加第四个单词,由于已经到末尾单词了,不会添加平均空格了。整个过程结束,最终空格数在三个间隔中应该是 2 2 1。
posted on 2022-06-19 13:13  我不想一直当菜鸟  阅读(370)  评论(0编辑  收藏  举报