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:
L:
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.
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.
Analysis:
The idea of my solution is not efficient, but easily understood.
It is easier to follow the Python code below.
Step 1: Find the level number for each word. Assuming that there is at least 1 space between two words.
Step 2: Find the number of word in each level and the total spaces needed in that level.
Step 3: Compute the number of spaces M in each level that is needed between two words. If the spaces are not evenly distributed. Compute the number of words where 1+M spaces is needed, and the between the rest of words there needed M spaces.
Step 4: Write the levels which has only one word to the result.
Step 5: Find the levels that the last word that level ends with '.' (which is the sentence end).
Step 6: Write the levels to the result.
Step 7: Return result.
Code(Python):
class Solution:
# @param words, a list of strings
# @param L, an integer
# @return a list of strings
def fullJustify(self, words, L):
lens = 0 # word length + single space in current level
result = [] # result list of strings
single_level = [] # list of strings in current level
for word in words:
lens += len(word)
if lens <= L:
single_level.append(word) # add word into current level
lens += 1 # add single space length
else: #if word cannot be in current level
#get result string add to final results
result.append(self.proc_sinlge_lev(single_level, L, False))
#refresh the current level
single_level = []
single_level.append(word)
lens = len(word) + 1
#handle the last level of words
result.append(self.proc_sinlge_lev(single_level, L, True))
#return final result
return result
# @param single_level, a list of strings
# @param L, an integer
# @param last, an bool (True if current level is the last level)
def proc_sinlge_lev(self,single_level, L, last):
#last level no extra spaces inserted
if last == True:
if len(single_level) == 1: #only 1 word in current level
str_lev = single_level[0].ljust(L)
else:
str_lev = "" #result string
for str in single_level[0:-1]:
str_lev += str.ljust(len(str)+1) # 1 is a single space
str_lev += single_level[-1] # add the last word
str_lev = str_lev.ljust(L) # fill out spaces
return str_lev
else:
# compute lens of this level
if len(single_level) == 1: # only 1 word in current level
str_lev = single_level[0].ljust(L)
else:
lev_len = sum(len(s) for s in single_level) # sum of word length in current level
sp = L-lev_len # total space numbers
first = sp % (len(single_level)-1) # how many spaces needed when the spaces can not be evenly divided
sp_s = sp / (len(single_level)-1) # how many spaces are needed between two words
str_lev ="" # result string
for str in single_level[0:-1]:
if first != 0: # add one more spaces from the left
str_lev += str.ljust(len(str)+sp_s+1)
first -=1
else:
str_lev += str.ljust(len(str)+sp_s)
str_lev += single_level[-1] #add last word
return str_lev
Code(C++):
class Solution {
public:
vector<string> fullJustify(vector<string> &words, int L) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
vector<string> res;
vector<int> lev;
int len=0;
int l=0;
for (int i=0;i<words.size();i++){
len +=words[i].size();
if (len<=L){lev.push_back(l);len++;}
else{l++; lev.push_back(l);len=words[i].size()+1;}
}
lev.push_back(-1);
vector<int> sp(l+1,L);
vector<int> sp_mode(l+1,0);
vector<int> nword(l+1,0);
for (int i=0;i<words.size();i++){
sp[lev[i]] -= words[i].size();
++nword[lev[i]];
}
for (int i=0;i<=l;i++){
if (nword[i]>1){
sp_mode[i] = sp[i]%(nword[i]-1);
sp[i] = sp[i]/(nword[i]-1);
}
}
res=vector<string>(l+1,"");
for (int i=0;i<words.size();i++){
if (nword[lev[i]]==1){
res[lev[i]] += words[i];
res[lev[i]] += string(sp[lev[i]],' ');
nword[lev[i]]=0;
}
}
vector<bool> flag(l+1,false);
int prev=-1;
for (int i=0;i<words.size();i++){
if (nword[lev[i]]>0){
if (lev[i+1]!=lev[i]){
if (words[i][words[i].size()-1]=='.') {
if (prev==-1){
prev = i;
}else{
flag[lev[prev]]=false;
prev = i;
}
flag[lev[i]]=true;
}
}
}
}
for (int i=0;i<words.size();i++){
if (nword[lev[i]]>0){
if (flag[lev[i]]==true){
res[lev[i]] += words[i];
nword[lev[i]]--;
if (nword[lev[i]]>0){
res[lev[i]]+=' ';
}else{
res[lev[i]]+=string(L-res[lev[i]].size(),' ');
}
}else{
res[lev[i]] += words[i];
nword[lev[i]]--;
if (nword[lev[i]]>0){
if (sp_mode[lev[i]]>0){
res[lev[i]] += string(sp[lev[i]]+1,' ');
sp_mode[lev[i]]--;
}else{
res[lev[i]] += string(sp[lev[i]],' ');
}
}
}
}
}
return res;
}
};
Hi, I tried your code in OJ but cannot pass test cases. I think for the line with '.' in the end, you dealt with it by adding no space between words. However, the question only require that for the last line, you do not add space, but for the lines in the middle, you still need to divide space evenly.
ReplyDeleteThanks for your reply. I have checked again the code again and I have made slight changes on my code, now it can pass the OJ.
Delete