518 字
3 分钟
3090. 每个字符最多出现两次的最长子字符串
3090. 每个字符最多出现两次的最长子字符串
题目描述
给你一个字符串 s,请找出满足每个字符最多出现两次的最长子字符串,并返回该子字符串的最大长度。
示例 1:
输入:s = "bcbbbcba"输出:4示例 2:
输入:s = "aaaa"输出:2解法思路
核心思想
这是一个不定长滑动窗口问题(越短越合法)。窗口内每个字符的出现次数都 是合法条件。右指针不断把新字符纳入窗口;一旦某个字符次数超过 2,就右移左指针收缩窗口,直到该字符重新合法。
用哈希表 cnt 维护窗口内各字符的出现次数。由于新字符是右指针刚加入的、唯一可能出现超限的就是 s[right] 本身,所以内层只用 while cnt[s[right]] > 2 这一个条件即可触发收缩,其余字符天然不可能超限。
算法步骤
- 初始化
ans = left = 0,cnt为空字典。 - 枚举
right,把s[right]计数加一。 while cnt[s[right]] > 2:把s[left]计数减一,left += 1(收缩直到刚加入的字符不超限)。- 用当前窗口长
right - left + 1更新ans。 - 返回
ans。
逐步举例
以 s = "bcbbbcba" 为例(期望答案 4):
| right | 字符 | 入窗后计数 | 收缩动作 | 窗口 | 长度 | ans |
|---|---|---|---|---|---|---|
| 0 | b | b:1 | — | [0,0]=“b” | 1 | 1 |
| 1 | c | b:1,c:1 | — | [0,1]=“bc” | 2 | 2 |
| 2 | b | b:2,c:1 | — | [0,2]=“bcb” | 3 | 3 |
| 3 | b | b:3,c:1 | 左移,b:2 | [1,3]=“bcb” | 3 | 3 |
| 4 | b | b:3→2 | 左移两次 | [3,4]=“bb” | 2 | 3 |
| 5 | c | b:2,c:1 | — | [3,5]=“bbc” | 3 | 3 |
| 6 | b | b:3→2 | 左移一次 | [4,6]=“bcb” | 3 | 3 |
| 7 | a | 含 a,b:2,c:1 | — | [4,7]=“bcba” | 4 | 4 |
遍历结束,最长合法子串长度为 4。
题解
class Solution: def maximumLengthSubstring(self, s: str) -> int: ans = left = 0 cnt = {} for right, ch in enumerate(s): cnt[ch] = cnt.get(ch, 0) + 1 while cnt[ch] > 2: cnt[s[left]] -= 1 left += 1 ans = max(ans, right - left + 1) return ansimport syssys.path.insert(0, "/workspace/projects/source/coding/sliding-window-two-pointers/02-variable-sliding-window/3090-max-two-occurrences")from solution import Solutionimport unittest
class TestMaximumLengthSubstring(unittest.TestCase): def setUp(self): self.solution = Solution()
def test_example1(self): self.assertEqual(self.solution.maximumLengthSubstring("bcbbbcba"), 4)
def test_example2(self): self.assertEqual(self.solution.maximumLengthSubstring("aaaa"), 2)
def test_all_unique(self): self.assertEqual(self.solution.maximumLengthSubstring("abcdef"), 6)
def test_single_char(self): self.assertEqual(self.solution.maximumLengthSubstring("a"), 1)
def test_two_chars(self): self.assertEqual(self.solution.maximumLengthSubstring("ab"), 2)
if __name__ == "__main__": unittest.main()复杂度分析
- 时间复杂度:O(n),左右指针各遍历一次序列
- 空间复杂度:O(|Σ|),
Σ为字符集大小(本题仅 26 个小写字母可视为 O(1))
3090. 每个字符最多出现两次的最长子字符串
https://h1s97x.github.io/posts/coding/coding-3090-max-two-occurrences/