418. 屏幕可显示句子的数量 🔒
题目描述
给你一个 rows x cols 的屏幕和一个用 非空 的单词列表组成的句子,请你计算出给定句子可以在屏幕上完整显示的次数。
句子中的单词顺序必须保持不变,并且不能将一个单词分成两行。一行中的两个连续单词必须用空白分开。
示例 1:
输入:sentence = ["hello", "world"], rows = 2, cols = 8 输出:1 解释: hello--- world--- 字符 '-' 表示屏幕上的一个空白位置。
示例 2:
输入:sentence = ["a", "bcd", "e"], rows = 3, cols = 6 输出:2 解释: a-bcd- e-a--- bcd-e- 字符 '-' 表示屏幕上的一个空白位置。
示例 3:
输入:sentence = ["i", "had", "apple", "pie"], rows = 4, cols = 5 输出:1 解释: i-had apple pie-i had-- 字符 '-' 表示屏幕上的一个空白位置。
提示:
1 <= sentence.length <= 1001 <= sentence[i].length <= 10sentence[i]由小写英文字母组成。1 <= rows, cols <= 2 * 104
解法
方法一:贪心
思考
逐词判断当前行能否放下,行数可达 \(10^4\),句子会循环多次,指针在单词间来回移动较繁琐。
把句子连成带尾空格的环 \(s\),用 \(\textit{cur}\) 表示已经覆盖的字符数。每一行先加上 \(\textit{cols}\):若落点是空格,说明刚好结束一个单词,再前进一格;否则回退到上一个空格,相当于把未写完的单词放到下一行。
整句出现次数即 \(\lfloor \textit{cur}/|s| \rfloor\)。尾空格把「单词之间必须有空格」编码进环上,回退保证不会把单词拆开。
我们将句子的每个单词拼接上一个空格,然后把句子拼接起来,得到字符串 \(s\)。例如,对于句子 ["hello", "world"],得到的字符串为 "hello world "。记 \(s\) 的长度为 \(m\)。
接下来,我们使用贪心的方法,找到最大的可显示句子数。定义一个变量 \(cur\),表示当前已经在屏幕上显示的字符串的长度,初始时 \(cur=0\)。
我们循环 \(rows\) 次,每次循环中,我们首先将 \(cur\) 增加 \(cols\),如果 \(s[cur \bmod m]\) 是一个空格,说明我们可以将完整的若干个单词放置到当前行,因此我们将 \(cur\) 增加一个额外的 \(1\);否则,说明我们需要回退 \(cur\),直到 \(cur\) 指向的字符是一个空格为止。然后继续下一次循环。
循环结束,返回 \(\lfloor \frac{cur}{m} \rfloor\) 即可。
时间复杂度 \(O(rows \times M)\),空间复杂度 \(O(L)\)。其中 \(M\) 是单词的最大长度,而 \(L\) 是单词的总长度。
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |