leetcode:68.文本左右对齐
题目描述:
给定一个单词数组和一个长度 maxWidth,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。
你应该使用“贪心算法”来放置给定的单词;也就是说,尽可能多地往每行中放置单词。必要时可用空格 ' ' 填充,使得每行恰好有 maxWidth 个字符。
要求尽可能均匀分配单词间的空格数量。如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数。
文本的最后一行应为左对齐,且单词之间不插入额外的空格。
说明:
单词是指由非空格字符组成的字符序列。
每个单词的长度大于 0,小于等于 maxWidth。
输入单词数组 words 至少包含一个单词。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/text-justification
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
示例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 "
]
题目难度:困难
分析:
题目意思比较好理解,无非就是单词+空格+单词+空格...
然后计算所有长度,取每行的最大长度即可。难在确定了每行应放的单词后,剩余的空格怎么分配?我的思路就是:当我确定了每行的单词个数以及单词的长度和后,用需要补全的空格数
以及单词间的间隙数
来计算最后的每个间隙需要补全的空格数
。代码如下:
java:
class Solution {
public List<String> fullJustify(String[] words, int maxWidth) {
// 用来存储最终结果
List<String> res = new ArrayList<>();
// 用来存储临时单词,即每一行拼接之前的所有单词
List<String> tempList = new ArrayList<>();
// 上面临时单词的长度和
int currentLength = 0;
// 用来拼接临时单词
StringBuilder currentStr = new StringBuilder();
for (int i = 0; i < words.length; i++) {
// 临时单词
String tempStr = words[i];
// 计算拼接完单词后的最小长度是否会超出maxWidth,如果是2个单词即长度等于2个单词的长度加1个空格,
// 3个单词就是3个单词长度加2个空格,以此类推,此时当前单词还没有放入tempList,所以size就是空格数
int tempCurrentLength = currentLength + tempStr.length() + tempList.size();
if (tempCurrentLength == maxWidth) {
// 如果正好相等,那么按照一个单词一个空格添加到currentStr即可
tempList.add(tempStr);
for (String s : tempList) {
currentStr.append(s);
currentStr.append(" ");
}
// 这里是去掉上方循环后多余的一个空格
currentStr = new StringBuilder(currentStr.substring(0, currentStr.length() - 1));
} else if (tempCurrentLength > maxWidth) {
// 这是最复杂的情况,下一个单词加入会超过maxWidth的值
// 先计算一共需要多少个空格
int spaceCount = maxWidth - currentLength;
// 这里是间隙数,就是3个单词中间有两个间隙,4个单词有3个间隙,因为尾部是不允许有空格的
int space = tempList.size() - 1;
// 这里是单个间隙需要多少空格
int singleSpaceCount = 0;
// 这里是剩余的空格,因为可能会出现不平均的情况,比如5个空格,3个间隙,那么应该是221分配
int remainderCount = 0;
// 因为会出现一行就一个长单词的情况,所以间隙数可能为0
if (space != 0) {
// 还用5个空格,3个间隙举例,那么singleSpaceCount = 1,remainderCount = 2
// 代表3个间隙每个间隙一个空格,还剩余2个空格,至于这2个怎么分配,下面会说到
singleSpaceCount = spaceCount / space;
remainderCount = spaceCount % space;
}
for (int j = 0; j < tempList.size(); j++) {
String s = tempList.get(j);
currentStr.append(s);
// 添加完单词后,循环插入空格,注意:最后一个单词后面不需要空格
for (int m = 0; m < singleSpaceCount && j != tempList.size() - 1; m++) {
currentStr.append(" ");
// 这里就是remainderCount剩余空格的分配,因为题目有说到:左侧空格应大于右侧
// 所以当remainderCount>0时,每次多分配一个,即可处理完所有的remainderCount
if (remainderCount > 0) {
currentStr.append(" ");
remainderCount--;
}
}
}
// 这里是处理前面说到的一个长单词单独占据一行的情况,需要在最后补全空格
if (currentStr.length() < maxWidth) {
int n = maxWidth - currentStr.length();
for (int j = 0; j < n; j++) {
currentStr.append(" ");
}
}
// 这个i--是因为当前单词长度和大于maxWidth了,没有进行拼接,所以需要回退继续下一轮
i--;
} else {
// 最后只剩小于的情况,那么长度累加,单词放入临时集合存储,继续循环
currentLength += tempStr.length();
tempList.add(tempStr);
// 此时没有达到>或者=的情况,所以用continue结束循环
continue;
}
// 经过前面判断,如果此时是>或者=的情况,那么直接把上方处理好的currentStr添加到res,
// 然后清空currentStr、tempList、currentLength
res.add(currentStr.toString());
currentStr = new StringBuilder();
tempList.clear();
currentLength = 0;
}
// 还有种情况就是最后单词不够一行,那么此时tempList里必然还存有元素,单独作为一行即可
if (tempList.size() > 0) {
for (String s : tempList) {
currentStr.append(s);
currentStr.append(" ");
}
// 最后补全空格,添加到res即可
if (currentStr.length() < maxWidth) {
int n = maxWidth - currentStr.length();
for (int i = 0; i < n; i++) {
currentStr.append(" ");
}
}
res.add(currentStr.toString());
}
return res;
}
}
总结:
题目在困难级别里应该算作较为简单的了,思路也比较清晰,难在代码的书写篇幅过大,需要考虑的情况也较多,有debug调试会轻松许多。
还没有评论,来说两句吧...