题干
给定一个单词数组 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",
因为最后一行应为左对齐,而不是左右两端对齐。
第二行同样为左对齐,这是因为这行只包含一个单词。
题解
使用模拟的方法,在遍历words的过程当中,维护一个滑动窗口,标识当前计算的行的开头和结尾的单词,这个时候有三种情况:
- 当前行是最后一行,采用左对齐方式,那么每一个单词之间插入一个空格,不够
maxWidth则在最后补充空格 - 当前行不是最后一行,且当前行只有一个单词,那么在这个单词后补足一定数量的空格,使行长度达到
maxWidth - 当前行不是最后一行,且当前行不只有一个单词,那么需要把空格均匀分配在单词中间,且要满足左侧空格数大于右侧空格数。假设当前行可以容纳的空格数为
spaceLen,可以维护一个临时的数组spaceNums用来存放各个单词后的空格数量,从左到右循环遍历spaceNums将spaceNums[i] + 1,直到spaceLen为0,即可满足条件。
func fullJustify(words []string, maxWidth int) []string {
var ans []string
wordNum := len(words)
// 当前行的字符数量
lineLen := 0
// 当前行的单词在原数组中的起始、终止下标
lineStart, lineEnd := 0, 0
// 当前已处理的单词数量
processed := 0
// 当处理完所有的单词之后退出循环
for processed < wordNum {
// 当前行是最后一行的时候,每个单词中间有一个空格,还不够的话在后面补充空格
if lineEnd == wordNum {
tmpLine := ""
// 每个单词后面都增加一个空格
for i := lineStart; i <= lineEnd-1; i++ {
tmpLine += words[i]
if i != lineEnd-1 {
tmpLine += " "
}
processed++
}
// 在后面补充空格
for len(tmpLine) < maxWidth {
tmpLine += " "
}
ans = append(ans, tmpLine)
continue
}
// 当前行不是最后一行的时候,要把空格平均分配在当前行的单词之间
curWordLen := len(words[lineEnd])
lineLen += curWordLen
lineWordNum := lineEnd - lineStart + 1
// 如果超出了最大的字符数就要立即计算当前行,否则就将右指针往右推,代表当前行还能装下新的单词
if lineLen+lineWordNum-2 >= maxWidth {
// 存放当前行的临时变量
tmpLine := ""
// 当前行可以容纳的空格总数量
spaceLen := maxWidth - (lineLen - curWordLen)
// 将空格均匀的分配到单词中间
// 用一个数组spaceNums存放当前行每个单词后面应该有多少空格
// 如果当前行只有一个单词,那么他后面的空格数量应该等于空格总数
// 否则将空格均匀分配
spaceNums, pos := make([]int, lineEnd-lineStart-1), 0
if len(spaceNums) == 0 {
spaceNums = append(spaceNums, spaceLen)
} else {
for spaceLen > 0 {
spaceNums[pos]++
spaceLen--
pos = (pos + 1) % (lineEnd - lineStart - 1)
}
}
for i := lineStart; i <= lineEnd-1; i++ {
tmpLine += words[i]
processed++
if i-lineStart >= len(spaceNums) {
break
}
for j := 1; j <= spaceNums[i-lineStart]; j++ {
tmpLine += " "
}
}
// 将计算结果加入最终结果中,并将滑动窗口右移
ans = append(ans, tmpLine)
lineStart = lineEnd
lineLen = 0
} else {
lineEnd++
}
}
return ans
}