字符串题目:写字符串需要的行数

文章目录

题目

标题和出处

标题:写字符串需要的行数

出处:806. 写字符串需要的行数

难度

3 级

题目描述

要求

给你由小写英语字母组成的字符串 s \texttt{s} s 和一个表示每个小写英语字母的宽度的像素数的数组 widths \texttt{widths} widths。特别地, widths[0] \texttt{widths[0]} widths[0] 表示 ‘a’ \texttt{`a'} ‘a’ 的宽度, widths[1] \texttt{widths[1]} widths[1] 表示 ‘b’ \texttt{`b'} ‘b’ 的宽度,以此类推。

你要将 s \texttt{s} s 写在若干行中,每一行的最大长度不超过 100 \texttt{100} 100 像素。从 s \texttt{s} s 的第一个字符开始,在第一行写尽可能多的字母使得总宽度不超过 100 \texttt{100} 100 像素。然后在第二行继续写尽可能多的 s \texttt{s} s 中的字符。该过程持续到 s \texttt{s} s 的全部字符都写完。

返回长度为 2 \texttt{2} 2 的数组 result \texttt{result} result:

  • result[0] \texttt{result[0]} result[0] 是总行数;
  • result[1] \texttt{result[1]} result[1] 是最后一行的宽度的像素数。

示例

示例 1:

输入: widths   =   [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10],   s   =   "abcdefghijklmnopqrstuvwxyz" \texttt{widths = [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10], s = "abcdefghijklmnopqrstuvwxyz"} widths = [10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10], s = "abcdefghijklmnopqrstuvwxyz"
输出: [3,60] \texttt{[3,60]} [3,60]
解释:你可以按如下方法写 s \texttt{s} s:
abcdefghij   //   100   像素 \texttt{abcdefghij // 100 像素} abcdefghij // 100 像素
klmnopqrst   //   100   像素 \texttt{klmnopqrst // 100 像素} klmnopqrst // 100 像素
uvwxyz       //   60   像素 \texttt{uvwxyz ~~~~// 60 像素} uvwxyz     // 60 像素
一共有 3 \texttt{3} 3 行,最后一行的宽度是 60 \texttt{60} 60 像素。

示例 2:

输入: widths   =   [4,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10],   s   =   "bbbcccdddaaa" \texttt{widths = [4,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10], s = "bbbcccdddaaa"} widths = [4,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10], s = "bbbcccdddaaa"
输出: [2,4] \texttt{[2,4]} [2,4]
解释:你可以按如下方法写 s \texttt{s} s:
bbbcccdddaa   //   98   像素 \texttt{bbbcccdddaa // 98 像素} bbbcccdddaa // 98 像素
a             //   4   像素 \texttt{a ~~~~~~~~~~// 4 像素} a           // 4 像素
一共有 2 \texttt{2} 2 行,最后一行的宽度是 4 \texttt{4} 4 像素。

数据范围

  • widths.length = 26 \texttt{widths.length} = \texttt{26} widths.length=26
  • 2 ≤ widths[i] ≤ 10 \texttt{2} \le \texttt{widths[i]} \le \texttt{10} 2≤widths[i]≤10
  • 1 ≤ s.length ≤ 1000 \texttt{1} \le \texttt{s.length} \le \texttt{1000} 1≤s.length≤1000
  • s \texttt{s} s 只包含小写英语字母

解法

思路和算法

这道题只需要模拟写字符串的过程,并计算使用的行数和当前行的宽度即可。

由于字符串 s s s 的长度大于 0 0 0,因此至少需要 1 1 1 行。

用 linesCount \textit{linesCount} linesCount 表示行数, curWidth \textit{curWidth} curWidth 表示当前行的宽度。初始化 linesCount = 1 \textit{linesCount}=1 linesCount=1 和 curWidth = 0 \textit{curWidth} = 0 curWidth=0。

从左到右遍历字符串 s s s,对于每个字符,获得该字符的宽度 width \textit{width} width,进行如下操作:

  • 如果 curWidth + width ≤ 100 \textit{curWidth} + \textit{width} \le 100 curWidth+width≤100,则该字符可以写入当前行,因此 linesCount \textit{linesCount} linesCount 的值不变,将 curWidth \textit{curWidth} curWidth 的值增加 width \textit{width} width;

  • 如果 curWidth + width > 100 \textit{curWidth} + \textit{width} > 100 curWidth+width>100,则该字符不可以写入当前行,否则当前行的总宽度超过 100 100 100 像素,因此该字符必须写在新的一行,将 linesCount \textit{linesCount} linesCount 的值加 1 1 1,将 curWidth \textit{curWidth} curWidth 的值设置为 width \textit{width} width。

遍历结束之后,即有 result [ 0 ] = linesCount , result [ 1 ] = curWidth \textit{result}[0]=\textit{linesCount},\textit{result}[1]=\textit{curWidth} result[0]=linesCount,result[1]=curWidth。

上面的内容是解题过程。具体实现时,有一些细节问题需要考虑。

  • 对于字符 c c c,其取值范围是 ‘a’ \text{`a'} ‘a’ 到 ‘z’ \text{`z'} ‘z’, c − ‘a’ c - \text{`a'} c−‘a’ 的取值范围是 0 0 0 到 25 25 25,和 widths \textit{widths} widths 的下标对应。因此,字符 c c c 的宽度为 widths [ c − ‘a’ ] \textit{widths}[c - \text{`a'}] widths[c−‘a’]。

  • 题目中明确说明了每一行最多 100 100 100 像素,因此可以在代码中使用数字 100 100 100 表示每一行的最大宽度。更好的做法是声明常量 MAX_WIDTH \textit{MAX\_WIDTH} MAX_WIDTH,将该常量的值设为 100 100 100,然后用该常量表示每一行的最大宽度。使用常量的好处是常量名称可以体现含义,增加代码的可读性,而且更有利于程序的可扩展性。

代码

class Solution {
    public int[] numberOfLines(int[] widths, String s) {
        final int MAX_WIDTH = 100;
        int linesCount = 1, curWidth = 0;
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            int width = widths[c - 'a'];
            if (curWidth + width <= MAX_WIDTH) {
                curWidth += width;
            } else {
                linesCount++;
                curWidth = width;
            }
        }
        return new int[]{linesCount, curWidth};
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要遍历字符串 s s s 一次。

  • 空间复杂度: O ( 1 ) O(1) O(1)。

上一篇:字符串题目:Z 字形变换


下一篇:冲刺大厂每日算法&面试题,动态规划21天——第十六天