[Leetcode] text justification 文本对齐

Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified.

You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces' 'when necessary so that each line has exactly L characters.

Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right.

For the last line of text, it should be left justified and no extra space is inserted between words.

For example,
words:["This", "is", "an", "example", "of", "text", "justification."]
L:16.

Return the formatted lines as:

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

Note: Each word is guaranteed not to exceed L in length.

click to show corner cases.

Corner Cases:
  • A line other than the last line might contain only one word. What should you do in this case?
    In this case, that line should be left-justified.

题意:

  1)给定单词数组和指定长度L,以左右对齐的形式,排列单词使每行字符个数为L;

  2)每行尽可能的多放单词,剩余的部分放“ ”以确保每行字符的个数;

  3)单词之间的空格,尽量均匀分布,若没法均匀分布,左边的单词之间均匀的放多余空格;

  4)最后一行,左靠齐,单词之间仅放一个空格,不足的右补齐。

思路:从词组里面取出一个单词,计算其长度,小于L,则,再取出一个词,考虑整个长度是否小于L,若是,则继续加词。其中要注意的是,每个单词之间至少有一个空格,所以在计算时要考虑空格的个数,显然,空格数等于目前单词的个数减1。这个过程的小技巧是,先计算当前行的字符串长度和和下一个单词的总长度是否小于L,在确定是否加上下一个单词,具体见代码。这样每一行的单词个数确定好了,这样就遇到一个问题,就是,每个单词之间的空格数不确定。在此之前,我们还要考虑如何插入空格。常规的思路是:使用中间变量(用数组)先将每个单词存好,然后等到确定好空格之间的个数后,再连接起来。现在就再次转到如何处理空格个数的问题了:

若该行只有一个单词,这个好办,剩下的直接补上“ ”就行;若有多个了?我们先用总的空格数除以空格个数,求得,每个单词之间只要有几个空格,然后再求余,求得多余的,再按从左往右的方式靠左的单词之间多插入一个“ ”。这样以后,又碰到一个问题,就是如何将其连接起来?常规思路是:先遍历整个数组中的string,将每个单词后面插入均等的个数的空格,然后在遍历左边几个单词加上余下的空格。

这样还是会遇到一个问题,那就是最后一行的处理方式和别的行不一样,这样,就可以在考虑某一个数的时候,考虑单词是否越界的问题,以保存,最后一行,单独处理。

这样写的过程中还是出错了,参考了小小程序媛,自己写 ,一次通过的还是很难啊!!

 1 class Solution {
 2 public:
 3     vector<string> fullJustify(vector<string> &words, int L) 
 4     {
 5         if(words.empty())   return vector<string>();
 6 
 7         vector<string> ret;
 8 
 9         int sumLen=words.size();
10 
11         vector<string> temp;    //临时向量,只放字符串
12         int curLen=0,count=0;   //该行的长度,和该行字符串的个数
13         for(int i=0;i<sumLen;++i)
14         {   //注意if的条件使用
15             if((curLen+words[i].size()+count)<=L)
16             {
17                 ++count;
18                 curLen+=words[i].size();
19                 temp.push_back(words[i]);
20                 continue;
21             }
22             else
23             {   //仅一个,剩下以空格补上
24                 if(count==1)
25                 {
26                     string str=temp[0];
27                     while(str.size()<L)
28                     {
29                         str+=" ";
30                     }
31                     ret.push_back(str);
32                 }
33                 else
34                 {
35                     string str;
36                     //该行总的空格,
37                     int extraSpace=L-curLen;    
38                     int everySpace=extraSpace/(count-1);    //每个间隔的空格
39                     int frontSpace=extraSpace%(count-1);    //还需重新增加的空格
40 
41                     for(int k=0;k<count-1;++k)
42                     {
43                         int j=0;
44                         while(j<everySpace)   //在插好的字符串后面接上空格
45                         {
46                             temp[k]+=" ";
47                             ++j;
48                         }
49                     }
50                     for(int k=0;k<frontSpace;++k)   //重新接上还需增加的空格
51                     {
52                         temp[k]+=" ";
53                     }
54                     for(int k=0;k<count;++k)       //转换成字符串
55                     {
56                         str+=temp[k];
57                     }
58                     ret.push_back(str);     //输出
59                 }
60             }
61             //清零,准备下一行
62             temp.clear();
63             count=0;
64             curLen=0;
65             --i;        //for循环中,i是先++后在判断是否满足条件,所以要— —
66         }  
67         //处理最后一行,左对齐,一下执行的条件是,在for循环中if中的continue中断
68         if(count==1)
69         {
70             string str=temp[0];
71             while(str.size()<L)
72             {
73                 str+=" ";
74             }
75             ret.push_back(str);
76         }  
77 
78         if(count>1)
79         {
80             string str;
81             for(int k=0;k<count-1;++k)
82             {
83                 str+=temp[k]+" ";
84             }
85             str+=temp[count-1];
86             while(str.size()<L)
87                 str+=" ";
88             ret.push_back(str);
89         }
90         return ret;
91     }
92 };

好吧,写完之后,代码比较长,上网拜读了Grandyang的写法,他(她)的写法,直接省去了中间数组,在将单词的连接和空格的处理在一起考虑了,所以代码比我的简洁很多。其大致思路为:找到每行所需的单词数,通过下标 j 是否等于words.size(),判断是否到了最后一行,分为两种情况考虑,一、最后一行,二、不是最后一行。通过确定每个单词的之后的空格数来实现,单词的连接和空格的插入同时进行。特别是针对,不是最后一行的情况,处理的比较巧妙,多个单词的情况,若是能,均分,everySpace就是均值,不能,则先给左边的空格多加1(体会这个),减去这个串空格,剩下的不会影响均分的值。针对多个时,遍历到最后一个时everySpace=space=0。感觉好绕,哈哈,懂了就是懂了,但还是不好想啊,这种处理方式,牛。多想想。这里直接给出其代码,并针对性的分析语句,若还是有不懂的,移步去看原文。

 1 class Solution {
 2 public:
 3     vector<string> fullJustify(vector<string> &words, int L) 
 4     {
 5         vector<string> res;
 6         int i=0;
 7 
 8         while(i<words.size())
 9         {
10             int j=i;    //记录每行起点的下标
11             int rowLen=0;
12 
13             while(j<words.size() && rowLen+words[j].size()+j-i<=L)
14                 rowLen+=words[j++].size();
15             
16             int space=L-rowLen;     //每行中空格总数
17             string rowStr;
18             for(int k=i;k<j;++k)
19             {
20                 rowStr+=words[k];   //space==0说明一行中仅有一个单词,且长度为L
21                 if(space>0)
22                 {
23                    int everySpace;  //每个单词之间的间隔
24                    if(j==words.size())  //最后一行的情况
25                    {
26                         if(j-k==1)      //只有一个单词剩下全为' '
27                             everySpace=space;
28                         else            //多个单词,每个之间插入一个' '
29                             everySpace=1;
30                    }
31                    else
32                    {
33                        if(j-k-1>0)  //多个单词的情况下,每个之间有一个的情况下判断剩下多余的空格的放法,好好体会这个if
34                        {
35                            if(space%(j-k-1)==0)         //均分
36                                 everySpace=space/(j-k-1);
37                            else
38                            {
39                                everySpace=space/(j-k-1)+1;  //左边的多放1个' '
40                            }
41                        }
42                        else      //剩下一个单词
43                             everySpace=space;
44                    } 
45                    rowStr.append(everySpace,' ');
46                    space-=everySpace;
47                 }
48             }//end for
49             res.push_back(rowStr);
50             i=j; 
51         }
52         return res;      
53     }
54 };
原文地址:https://www.cnblogs.com/love-yh/p/7085285.html