刷题打卡:字符串操作の 文本左右对齐

219 阅读3分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一、题目描述:

文本左右对齐

给定一个单词数组 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",
     因为最后一行应为左对齐,而不是左右两端对齐。       
     第二行同样为左对齐,这是因为这行只包含一个单词。

二、思路与实现:

思路:

这题关键还是在于读懂题意,提取几个关键点

每行恰好需要有maxWidth字符,也就是说不满也得补足(包括最后一行)

每一行左右两端对齐,而最后一行左对齐,那么前面的空格都补在中间,最后一行补在后面

如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数,多出来的空格也是需要均分到前几个单词的,而不是全加到第一个单词后面(不理解的话跑下用例就知道了)

那么围绕着几个关键点就可以写代码了,主要思路就是用双指针遍历,判断单词总长度大于maxWidth时就要拼接出一行来(拼接过程就参照题目要求,具体看代码),然后慢指针指向快指针

最后快指针遍历完毕所有字符也就拼接完了

代码实现:

/**
* @param {string[]} words
* @param {number} maxWidth
* @return {string[]}
*/
var fullJustify = function (words, maxWidth) {
    const res = [];
    let str = "";
    let tempLen = 0;
    //双指针
    let i = 0,
        j = 0
    //快指针遍历单词
    while (j < words.length) {
        const wordLen = words[j].length;
        //如果当前行还能容纳单词,则把长度累加上占坑
        if (tempLen + wordLen <= maxWidth - (j - i)) { //每个单词间至少要有一个空格,按照最极限来占位
            tempLen += wordLen;
            j++;
        } else {
            //如果当前行无法容纳单词了,则需要结算一下
            //先计算需要补充的空格数
            let spaceNum
            const wordNum = j - i;
            //用空余长度除以间隔数,如果只有一个单词moreSpace设为0
            let moreSpace = (maxWidth - tempLen) % (wordNum - 1) || 0;
            if (wordNum === 1) {
                spaceNum = maxWidth - tempLen;
            } else {
                if (moreSpace === 0) {
                    //如果刚好除的开,则直接平分
                    spaceNum = (maxWidth - tempLen) / (wordNum - 1);
                } else {
                    spaceNum = (maxWidth - tempLen - moreSpace) / (wordNum - 1);
                }
            }
            //拼接字符串
            for (let k = i; k < j; k++) {
                str += words[k];
                //如果空格无法均分则从左到右每个单词加一个空格,直到多余空格分配完毕
                if (moreSpace-- > 0) {
                    str += " ";
                }
                //加上算好的空格数,最后一个单词不加空格(除非是唯一一个)
                if (k !== j - 1 || wordNum === 1) {
                    for (let num = 0; num < spaceNum; num++) {
                        str += " ";
                    }
                }
            }
            //拼接完字符串后添加到结果中去,并清空状态
            res.push(str);
            str = "";
            tempLen = 0;
            i = j; //慢指针指向快指针
        }
    }
    //当遍历结束,判断一下最后一行还有没有单词
    if (tempLen) {
        //拼接字符串
        for (let k = i; k < j; k++) {
            str += words[k];

            //最后一行除了末尾,一词一个空格,谁也不许多要!
            if (k !== j - 1) {
                str += " ";
            }
        }
        //最后补空格让长度到maxWidth
        while (str.length < maxWidth) {
            str += " ";
        }
        res.push(str);
    }
    return res;
};

三、总结:

本题细节比较多,不好把握,分清楚情况会好解决些!