题目:

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 exactlyL 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. "
]

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.

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

链接:  http://leetcode.com/problems/text-justification/    

题解:

这是一刷时放弃的第二题。当时可能没有专心读懂题目,所以没做什么尝试就放弃了,现在来试着解一下。

读完题目以后,想法是有几个点我们要分个击破:

  1. 首先要判断每一行能容纳多少单词,每两个单词间要有一个空格
  2. 在得到单词容量和必须的空格数后,我们计算剩余长度是多少,然后根据单词数目来evenly distributed剩余的空格,有点像Round Robin
  3. 找到潜在的边界情况并处理, 返回结果。

记录下第一次过的长code,修修补补了很久。 步骤如下:

  1. 首先我们初始化
    1. 一个结果集res, 一个StringBuilder sb用来做缓冲
    2. 一个int值widthLeft用来记录还剩下多少长度可以使用
    3. 一个int值lineWordCount 用来记录这一行已经使用了多少单词,为的是以后计算单词间有多少个slot要填
  2. 从头遍历给定数组
    1. 先取出current word并且求出word length
    2. 假如wordLen + sb.length() <= maxWitdh,说明我们可以将这个单词添加入当前行,进行以下步骤:
      1. 我们先把单词加入到这一行, sb.append(word)
      2. 我们再append一个空格" "
      3. 此时lineWordCount++, 更新剩余长度,减掉单词长度和空格长度widthLeft -= (wordLen + 1)
      4. 接下来要对widthLeft进行判断
        1. 假如widthLeft > 0, 我们不理会,继续处理下面的单词
        2. 假如widthLeft < 0,这时说明我们最后的空格多加了。我们需要把当前sb.toString()进行一下trim()然后加入到结果集中,并且重置witdhLeft,sb,以及lineWordCount
        3. 否则这时widthLeft == 0。我们需要判断lineWordCount是否为1
          1. 假如lineWordCount等于1,我们把sb加入到结果集合中,重置变量们
          2. 否则,我们需要把最后的这一个空格抹去,在sb的第一个空格处再添加一个空格,sb.toString()加入到结果集中,并且重置变量们
    3. 第二种情况当前wordLen + sb.length() > maxWitdh,我们不能将此单词加入当前行,需要将当前行处理之后再把这个单词加入新一行,这里也分两种情况
      1. 假如lineWordCount = 1,这时候我们需要将这个单词后面的空格补齐,一直补到maxWitdh
      2. 否则,我们需要处理以下步骤
        1. 先抹掉sb中的最后一个空格,计算出一共需要多少个空格 totalSpaceAdd = widthLeft + 1, 以及有多少slot需要补空格,  slot = lineWordCount - 1
        2. 接下来,我们根据totalSpaceAdd和slot的关系,对sb中的每一个空格处进行补空格
        3. 最后将结果加入到结果集中,并且重置变量。假如没有处理当前单词,则i--倒退回去处理,否则要多写几行代码处理当前单词。
    4. 在结束的时候要判断一下是否sb.length依然大于0,否则我们还要将这最后一行进行处理。假如sb.length() > 0,按照题目要求我们在其后面补空格直到结束。

需要好好简化code,学习大牛们怎么写的。

Time Complexity - O(n), Space Complexity - O(n)

public class Solution {
public List<String> fullJustify(String[] words, int maxWidth) {
List<String> res = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int widthLeft = maxWidth;
int lineWordCount = 0;
for (int i = 0; i < words.length; i++) {
String word = words[i];
int wordLen = word.length();
if (wordLen + sb.length() <= maxWidth) {
sb.append(word);
sb.append(" ");
widthLeft -= (wordLen + 1);
lineWordCount++;
if (widthLeft < 0) {
res.add(sb.toString().trim());
widthLeft = maxWidth;
sb.setLength(0);
lineWordCount = 0;
} else if (widthLeft == 0) {
if (lineWordCount != 1) {
sb.setLength(sb.length() - 1);
for (int k = 0; k < sb.length(); k++) {
char c = sb.charAt(k);
if (c == ' ') {
sb.insert(k, ' ');
break;
}
}
}
res.add(sb.toString());
widthLeft = maxWidth;
sb.setLength(0);
lineWordCount = 0;
}
} else {
if (lineWordCount == 1) {
while (widthLeft > 0) {
sb.append(" ");
widthLeft--;
}
} else {
sb.setLength(sb.length() - 1);
int totalSpaceToAdd = widthLeft + 1;
int slots = lineWordCount - 1;
String s = sb.toString();
sb.setLength(0);
for (int k = 0; k < s.length(); k++) {
char c = s.charAt(k);
sb.append(c);
if (c == ' ') {
if (totalSpaceToAdd <= 0) {
continue;
}
int spaceToAdd = 0;
if (totalSpaceToAdd >= slots) {
spaceToAdd = (int) Math.ceil((double)totalSpaceToAdd / slots);
totalSpaceToAdd -= spaceToAdd;
slots--;
} else {
spaceToAdd = 1;
totalSpaceToAdd--;
}
while (spaceToAdd > 0) {
sb.append(' ');
spaceToAdd--;
}
}
}
}
widthLeft = maxWidth;
res.add(sb.toString());
sb.setLength(0);
lineWordCount = 0;
i--;
}
}
if (sb.length() != 0) {
while (widthLeft > 0) {
sb.append(" ");
widthLeft--;
}
res.add(sb.toString());
} return res;
}
}

精炼和更新:

改写了一下,把逻辑理顺了一点点。下面是改写的思路:

  1. 一开始仍然是初始化, 初始化结果集合res, 一个用来处理当前行的StringBuider sb,以及一个lineWordCount = 0
  2. 接下来遍历数组,先计算出当前单词word以及它的长度, 接下来我们主要分三种情况来考虑
    1. wordLen + sb.length() == maxWidth,这时我们找到一个结果,在sb中append当前单词,然后把sb.toString()加入到结果集合中,重置sb和lineWordCount
    2. wordLen + sb.length() < maxWidth,这时候说明我们仍然可以在当前行里塞单词,我们先append(word),再append一个空格" ", 更新lineWordCount++
    3. 否则说明当前wordLen + sb.length() > maxWidth,这时候我们必须对当前行sb进行处理,然后才可以继续后面的操作。对这种情况我们又可以分为两种子情况:
      1. 当lineWordCount == 1,这时候这一行只有一个单词,我们只需要在当前行sb的后面补足空格,直到补充到maxWidth为止
      2. 否则lineWordCount > 1,这时这一行有多个单词,我们执行一个分拆出来的函数distributeSpaces来把单词中的空格平均分配
      3. 经过上两步求出了当前行sb之后,我们可以把sb加入到结果集中,重置sb和lineWordCount,因为我们并没有处理当前单词,所以要减少index i,用i--来重新处理当前单词
  3. 主循环结束之后我们处理最后一行,根据题目意思,在sb中补空格直到maxWidth,然后将其加入到结果集中。
  4. 最后返回结果

关于辅助函数distributeSpaces,主要逻辑分为以下几个步骤:

  1. 当一行有多个单词的时候,我们需要把多余的空格均匀分配到每个已有的空格slot里,假如不够分,则尽量放到左边的slot里,这就有了我们的函数
  2. 我们的函数包括了上面主逻辑第3步的1和2小步,分为lineWordCount == 1时和lineWordCount > 1两种情况考虑
    1. 当lineWordCount == 1,这时候这一行只有一个单词,我们只需要在当前行sb的后面补足空格,直到补充到maxWidth为止
    2. 否则lineWordCount > 1,这时这一行有多个单词,我们执行一个分拆出来的函数distributeSpaces来把单词中的空格平均分配
      1. 这里我们首先计算出一共要分配多少个空格,这里newSpaceTotal = maxWidth - sb.length() + 1, 因为之前我们在每个单词后面都加入了一个空格,所以计算时要把这个考虑进去
      2. 我们有多少个slot可以插入, 因为每两个单词中间就算一个slot,所以slots = lineWordCount - 1
      3. 接下来我们先把sb转换为String s,再重置sb.setLength(0), 对于s, 从0到 s.legnth() - 2进行遍历 (不遍历最后一个空格)。
      4. 假如当前的字符为c,我们在sb中append(c), 假如c为空格的话,我们需要进行额外的判断:
        1. 当newSpaceTotal <= 0时, 用continue跳过
        2. 设置一个int spaceToAdd = 0,代表当前要加入的空格数
          1. 当newSpaceTotal > slots时, 我们计算这个slot可以添加多少个空格
            1. spaceToAdd = (int) Math.ceil((double) newSpaceTotal / slots), 这里要向上取整
            2. newSpaceTotal -= spaceToAdd
            3. slot--
          2. 否则slots数目大于等于newSpaceTotal, 我们最多每个slot可以分配一个space,所以
            1. spaceToAdd = 1
            2. newSpaceTotal--
          3. 接下来根据spaceToAdd的数目,我们在sb里面append(" ")。
public class Solution {
public List<String> fullJustify(String[] words, int maxWidth) {
List<String> res = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int lineWordCount = 0;
for (int i = 0; i < words.length; i++) {
String word = words[i];
int wordLen = word.length();
if (wordLen + sb.length() == maxWidth) {
sb.append(word);
res.add(sb.toString());
sb.setLength(0);
lineWordCount = 0;
} else if (wordLen + sb.length() < maxWidth) {
sb.append(word);
sb.append(" ");
lineWordCount++;
} else {
distributeSpaces(sb, maxWidth, lineWordCount);
res.add(sb.toString());
sb.setLength(0);
lineWordCount = 0;
i--;
}
}
if (sb.length() != 0) {
while (sb.length() < maxWidth) {
sb.append(" ");
}
res.add(sb.toString());
}
return res;
} private void distributeSpaces(StringBuilder sb, int maxWidth, int lineWordCount) {
if (lineWordCount == 1) {
while (sb.length() < maxWidth) {
sb.append(" ");
}
} else {
int newSpaceTotal = maxWidth - sb.length() + 1;
int slots = lineWordCount - 1;
String s = sb.toString();
sb.setLength(0);
for (int k = 0; k < s.length() - 1; k++) {
char c = s.charAt(k);
sb.append(c);
if (c == ' ') {
if (newSpaceTotal <= 0) {
continue;
}
int spaceToAdd = 0;
if (newSpaceTotal > slots) {
spaceToAdd = (int)Math.ceil((double)(newSpaceTotal) / slots);
newSpaceTotal -= spaceToAdd;
slots--;
} else {
spaceToAdd = 1;
newSpaceTotal--;
}
while (spaceToAdd > 0) {
sb.append(" ");
spaceToAdd--;
}
}
}
}
}
}

Reference:

https://leetcode.com/discuss/13610/share-my-concise-c-solution-less-than-20-lines

http://www.cnblogs.com/springfor/p/3896168.html

https://leetcode.com/discuss/30857/share-my-2-ms-30-lines-solution

https://leetcode.com/discuss/48959/easy-java-implementation

https://leetcode.com/discuss/20896/easy-understanding-solution

68. Text Justification的更多相关文章

  1. leetcode@ [68] Text Justification (String Manipulation)

    https://leetcode.com/problems/text-justification/ Given an array of words and a length L, format the ...

  2. 【一天一道LeetCode】#68. Text Justification

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  3. [leetcode]68. Text Justification文字对齐

    Given an array of words and a width maxWidth, format the text such that each line has exactly maxWid ...

  4. 68. Text Justification *HARD*

    Given an array of words and a length L, format the text such that each line has exactly L characters ...

  5. 【LeetCode】68. Text Justification

    Text Justification Given an array of words and a length L, format the text such that each line has e ...

  6. 68. Text Justification一行单词 两端对齐

    [抄题]: Given an array of words and a width maxWidth, format the text such that each line has exactly  ...

  7. [LeetCode] 68. Text Justification 文本对齐

    Given an array of words and a length L, format the text such that each line has exactly L characters ...

  8. 68. Text Justification (JAVA)

    Given an array of words and a width maxWidth, format the text such that each line has exactly maxWid ...

  9. Leetcode#68 Text Justification

    原题地址 没有复杂的算法,纯粹的模拟题 先试探,计算出一行能放几个单词 然后计算出单词之间有几个空格,注意,如果空格总长度无法整除空格数,前面的空格长度通通+1 最后放单词.放空格,组成一行,加入结果 ...

随机推荐

  1. oracle 11g 通过透明网关链接mysql

    之前转载过一篇在Windows上安装的,自己实际在centos上安装了一下.以下为安装记录: 一.操作系统环境 二.数据库环境(用oracle用户登录) 三.DG4ODBC 在Oracle DB 11 ...

  2. GITHUB 提交错误 Error: Permission denied (publickey) 解决

    1.  在开发机上生成自己的密钥 ssh-keygen -b 1024 -t rsa -b 指密钥对长度  -t 指加密方式 Enter file in which to save the key ( ...

  3. EAI概述

    企业的业务流程同时会涉及多个应用系统,因此要求这些系统能够协同,但接口,架构的不统一往往使得这些本应紧密集成的应用系统成了一个个“信息孤岛”.于是,企业应用集成(Enterprise Applicat ...

  4. 【狼窝乀野狼】Excel那些事儿

    在工作中我们常常遇到Excel表格,不管是数据的导入导出,还是财务统计什么都,都离不开Excel,Excel是我见过的最牛逼的一个软件(可能我的见识少)没有之一:如果你只停留在Excel处理数据,统计 ...

  5. xk01创建供应商保存的时候,提示错误“科目800001已经存在”

    解决方法:

  6. 【软件工程-Teamwork 2】必应词典软件手机版测试报告

    测试人员:聂健(N).居玉皓(J).吴渊渊(Wy).汪仁贵(Wr).吕佳辉(L).杜冰磊(D) 测试软件:必应词典软件手机版 版本:2.2.0版本(Android) 引言: 我们的测评报告的主体主要分 ...

  7. Document.defaultView

    Document.defaultView 引子 最近愚安在写一个可以将页面上的资源链接转为二维码以方便移动端浏览的chrome插件,由于dom操作并不多,而且作为插件不需要考虑跨 浏览器兼容性,所以并 ...

  8. java多线程状态转换

    http://www.mamicode.com/info-detail-517008.html 相关资料链接 我觉得下面这张图总结的很好

  9. javascript中alert()与console.log()的区别

    我们在做js调试的时候使用 alert 可以显示信息,调试程序,alert 弹出窗口会中断程序, 如果要在循环中显示信息,手点击关闭窗口都累死.而且 alert 显示对象永远显示为[object ]. ...

  10. ios开发之网络数据的下载与上传

    要实现网络数据的下载与上传,主要有三种方式 > NSURLConnection  针对少量数据,使用“GET”或“POST”方法从服务器获取数据,使用“POST”方法向服务器传输数据; > ...