【算法】Text Justification 文本对齐
题目
Given an array of words and a width maxWidth, format the text such that each line has exactly maxWidth 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 maxWidth 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.
Note:
A word is defined as a character sequence consisting of non-space characters only.
Each word's length is guaranteed to be greater than 0 and not exceed maxWidth.
The input array words contains at least one word.
Example 1:
Input:
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
Output:
[
"This is an",
"example of text",
"justification. "
]
Example 2:
Input:
words = ["What","must","be","acknowledgment","shall","be"]
maxWidth = 16
Output:
[
"What must be",
"acknowledgment ",
"shall be "
]
Explanation: Note that the last line is "shall be " instead of "shall be",
because the last line must be left-justified instead of fully-justified.
Note that the second line is also left-justified becase it contains only one word.
Example 3:
Input:
words = ["Science","is","what","we","understand","well","enough","to","explain",
"to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20
Output:
[
"Science is what we",
"understand well",
"enough to explain to",
"a computer. Art is",
"everything else we",
"do "
]
给出一组单词 words ,一个长度 maxWidth ,返回一个字符串数组满足如下条件:
- 所有字符长度均为 maxWidth
- 单词不可切割
- 每行字符串中,每个单词之间的空格大于等于 1 ,且均等分
- 如无法均等分,则左边的空格数比右边的多
- 最后一行单词之间只有一个空格,剩余空间用空格补齐
解题思路
主要就是计算每行字符串所需的单词 索引范围 和 空格数量 ,最后一行的处理也有些不同:
- 动态字符串长度 strCount,头位置 from ,尾位置 to,单词个数 wordCount = to - from + 1
- 判断条件就是 strCount + (当前单词长度)word.count + wordCount - 1 > mixWidth 时,from ~ to-1 就是符合条件的单词索引范围
- from ~ to-1 单词数量判断空格区间有几个:
- 单词数量<3时有一个,空格长度为 maxWidth - word.count,添加到单词后面
- 单词数量>3时有 单词数量 - 1 个
- 较大空格数量 larCount = (maxWidth - wordsLen) % (wordsCount - 1)
- 空格长度 spaceLen = (maxWidth - wordsLen) / (wordsCount - 1)
- 头 larCount 个空格区域有 spaceLen+1,之后都是 spaceLen 个空格
- 最后一个单词后面注意不添加空格
- 最后一行单词和空格交叉添加,最后位数不足用空格补齐
代码实现
Runtime: 8 ~ 20 ms
Memory: 21 MB
func fullJustify(_ words: [String], _ maxWidth: Int) -> [String] {
//添加字符串的数组
var result = [String]()
//动态字符串长度 strCount,头位置 from 尾位置to
var strCount = 0, from = 0, to = 0
//循环条件,to 在 words 范围内
while to < words.count {
// 空格数 spaceCount = to - from
// 字符数 + spaceCount > maxWidth , 或者 to 不在 words 范围中时,跳出循环,
while to < words.count && strCount + words[to].count + to - from <= maxWidth {
//循环条件内,添加动态字符串长度
strCount += words[to].count
//to 后移一位
to += 1;
}
// to 指向最后一个单词,应该跳出循环处理最后一行字符串
if to == words.count {
break
}
// from ~ to-1 的单词加上空格数满足条件,进行处理
let strEl = self.fillSpace(words, maxWidth: maxWidth, from: from, to: to - 1, wordsLen: strCount)
//将处理后的字符串添加进 result 中
result.append(strEl)
// 将 from 指向 to
from = to
// 重置 strCount 为 0
strCount = 0
}
//处理最后一行字符串
let strEl = self.fillLastLine(words, maxWidth: maxWidth, from: from, to: to - 1, wordsLen: strCount)
result.append(strEl)
//返回结果
return result
}
func fillSpace(_ words: [String], maxWidth: Int, from: Int, to: Int, wordsLen: Int) -> String{
var resStr = ""
let space = "*"
//单词数量 wordsCount
let wordsCount = to - from + 1
//较大空格的数量 larCount
var larCount = 0
//空格的长度 spaceLen
var spaceLen : Int = 1
if wordsCount<3 {
//单词数量小于3时,larCount=0,spaceLen=maxWidth - wordsLen
spaceLen = maxWidth - wordsLen
}else{
//单词数量大于等于3时,计算 larCount ,spaceLen
larCount = (maxWidth - wordsLen) % (wordsCount - 1)
spaceLen = (maxWidth - wordsLen) / (wordsCount - 1)
}
//from ~ to 单词加空格赋值给 resStr
for idx in from ... to {
resStr += words[idx]
var spaceLen1 = spaceLen
if larCount>0 {
//若 larCount大于0,索命本次空格数量为 spaceLen + 1
spaceLen1 += 1
// larCount - 1
larCount -= 1
}
//若不是最后一个单词,且并非只有一个单词时,添加空额
//若是最后一个单词,且只有一个单词时,添加空格
if (idx != to && wordsCount != 1) || (idx == to && wordsCount == 1) {
for _ in 0 ..< spaceLen1 {
resStr += space
}
}
}
//返回结果
return resStr
}
func fillLastLine(_ words: [String], maxWidth: Int, from: Int, to: Int, wordsLen: Int) -> String {
var resStr = ""
let space = "*"
//如果 from 小于 to
if from < to {
// from ~ to-1 单词和空格 加值到 resStr
for idx in from ..< to {
resStr += words[idx] + space
}
}
// resStr 加最后一个单词
resStr += words[to]
//剩余空间用空格补齐
let starNum = maxWidth - resStr.count
for _ in 0 ..< starNum {
resStr += space
}
//返回结果
return resStr
}