2981. 找出出现至少三次的最长特殊子字符串 I
题目描述
给你一个仅由小写英文字母组成的字符串 s 。
如果一个字符串仅由单一字符组成,那么它被称为 特殊 字符串。例如,字符串 "abc" 不是特殊字符串,而字符串 "ddd"、"zz" 和 "f" 是特殊字符串。
返回在 s 中出现 至少三次 的 最长特殊子字符串 的长度,如果不存在出现至少三次的特殊子字符串,则返回 -1 。
子字符串 是字符串中的一个连续 非空 字符序列。
示例 1:
输入:s = "aaaa" 输出:2 解释:出现三次的最长特殊子字符串是 "aa" :子字符串 "aaaa"、"aaaa" 和 "aaaa"。 可以证明最大长度是 2 。
示例 2:
输入:s = "abcdef" 输出:-1 解释:不存在出现至少三次的特殊子字符串。因此返回 -1 。
示例 3:
输入:s = "abcaba" 输出:1 解释:出现三次的最长特殊子字符串是 "a" :子字符串 "abcaba"、"abcaba" 和 "abcaba"。 可以证明最大长度是 1 。
提示:
3 <= s.length <= 50s仅由小写英文字母组成。
解法
方法一:二分查找 + 滑动窗口计数
思考
特殊子串由同一字符组成。长度 \(x\) 可行则 \(x-1\) 也可行,故二分 \(x\)。一段连续相同字符长度为 \(L\) 时,其中长为 \(x\) 的子串有 \(\max(0, L-x+1)\) 个,按字符累加后看是否达到 \(3\)。
\(n \le 50\),二分再线性计数即可。
我们注意到,如果一个长度为 \(x\) 且出现至少三次的特殊子字符串存在,那么长度为 \(x-1\) 的特殊子字符串也一定存在,这存在着单调性,因此我们可以使用二分查找的方法来找到最长的特殊子字符串。
我们定义二分查找的左边界 \(l = 0\),右边界 \(r = n\),其中 \(n\) 是字符串的长度。每次二分查找的过程中,我们取 \(mid = \lfloor \frac{l + r + 1}{2} \rfloor\),如果长度为 \(mid\) 的特殊子字符串存在,那么我们就将左边界更新为 \(mid\),否则我们就将右边界更新为 \(mid - 1\)。在二分查找的过程中,我们使用滑动窗口来计算特殊子字符串的个数。
具体地,我们设计一个函数 \(check(x)\),表示长度为 \(x\) 且出现至少三次的特殊子字符串是否存在。
在函数 \(check(x)\) 中,我们定义一个哈希表或长度为 \(26\) 的数组 \(cnt\),其中 \(cnt[i]\) 表示长度为 \(x\),且由第 \(i\) 个小写字母组成的特殊子字符串的个数。我们遍历字符串 \(s\),如果当前遍历到的字符为 \(s[i]\),那么我们将指针 \(j\) 向右移动,直到 \(s[j] \neq s[i]\),此时 \(s[i \cdots j-1]\) 就是一个长度为 \(x\) 的特殊子字符串,我们将 \(cnt[s[i]]\) 增加 \(\max(0, j - i - x + 1)\),然后将指针 \(i\) 更新为 \(j\)。
在遍历结束之后,我们遍历数组 \(cnt\),如果存在 \(cnt[i] \geq 3\),那么就说明长度为 \(x\) 且出现至少三次的特殊子字符串存在,我们返回 \(true\),否则返回 \(false\)。
时间复杂度 \(O((n + |\Sigma|) \times \log n)\),空间复杂度 \(O(|\Sigma|)\),其中 \(n\) 是字符串 \(s\) 的长度,而 \(|\Sigma|\) 表示字符集的大小,本题中字符集为小写英文字母,因此 \(|\Sigma| = 26\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
方法二:计数
思考
方法一多次扫描整串。\(n\) 很小时也可对每段 run 把长度为 \(1 \ldots L\) 的特殊串出现次数直接加进哈希表:长 \(j\) 的串在该 run 中出现 \(L-j+1\) 次。最后取出现次数 \(\ge 3\) 的最大长度。
与二分相比少了对数轮,但仍是按 run 做贡献,适合本题的短串。
时间复杂度 \(O(n)\)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |