600 字
3 分钟
2516. 每种字符至少取 K 个

2516. 每种字符至少取 K 个#

题目描述#

给你一个由字符 'a'、'b'、'c' 组成的字符串 s 和一个非负整数 k。每分钟,你可以选择取走 s 最左侧还是最右侧的那个字符。

你必须取走每种字符至少 k 个,返回需要的最少分钟数;如果无法取到,则返回 -1。

核心思想#

正难则反:反向滑动窗口。

从左右两端取字符,等价于中间保留一个窗口。求最小取走字符数,等价于求最大可保留窗口长度。

统计每种字符总数,窗口内每种字符最多允许保留 total[char] - k 个。用滑动窗口找满足条件的最长窗口,答案即为 n - 最长窗口长度。

算法步骤#

  1. 统计 s 中 'a'、'b'、'c' 的总数
  2. 若任一字符总数 < k,返回 -1
  3. 计算每种字符在窗口内最多允许保留的数量:need[c] = total[c] - k
  4. 滑动窗口找最长合法窗口(窗口内每种字符 ≤ need):
    • 右端点扩展,加入字符
    • 当某字符超过 need 时,收缩左端点
    • 更新最大窗口长度
  5. 返回 n - 最长窗口长度

逐步举例#

以 s = "aabbbcc", k = 1 为例:

统计:a=2, b=3, c=2

need(窗口内最多允许):a=1, b=2, c=1

rights[right]window超 need?收缩leftmax_len
0aa=1否—01
1aa=2a>1l=111
2ba=1,b=1否—12
3ba=1,b=2否—13
4ba=1,b=3b>2l=333
5cb=2,c=1否—33
6cb=2,c=2c>1l=663

最终 max_len = 3,答案 = 7 - 3 = 4。

验证:取走 s[0:3]="aab" 和 s[6:]="c",共 4 个字符,含 a=2≥1, b=1≥1, c=1≥1 ✓。

复杂度分析#

  • 时间复杂度:O(n)。统计 O(n),滑动窗口 O(n)。
  • 空间复杂度:O(1)。只维护 3 个字符的计数。

参考#

代码实现#

from collections import Counter
class Solution:
def takeCharacters(self, s: str, k: int) -> int:
cnt = Counter(s)
if any(cnt[c] < k for c in "abc"):
return -1
n = len(s)
need = {c: cnt[c] - k for c in "abc"}
window = {"a": 0, "b": 0, "c": 0}
left = max_len = 0
for right in range(n):
window[s[right]] += 1
while window[s[right]] > need[s[right]]:
window[s[left]] -= 1
left += 1
max_len = max(max_len, right - left + 1)
return n - max_len
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))
from solution import Solution
class TestTakeCharacters(unittest.TestCase):
def test_example1(self):
s = "aabaaaacaabc"
k = 2
self.assertEqual(Solution().takeCharacters(s, k), 8)
def test_example2(self):
s = "a"
k = 1
self.assertEqual(Solution().takeCharacters(s, k), -1)
def test_k_zero(self):
s = "abc"
k = 0
self.assertEqual(Solution().takeCharacters(s, k), 0)
def test_all_take(self):
s = "aabbcc"
k = 2
self.assertEqual(Solution().takeCharacters(s, k), 6)
def test_partial(self):
s = "abc"
k = 1
self.assertEqual(Solution().takeCharacters(s, k), 3)
def test_single_char(self):
s = "aaaa"
k = 2
self.assertEqual(Solution().takeCharacters(s, k), -1)
if __name__ == "__main__":
unittest.main()
2516. 每种字符至少取 K 个
https://h1s97x.github.io/posts/coding/coding-2516-take-k-characters/
作者
H1S97X
发布于
2026-08-18
许可协议
CC BY-NC-SA 4.0
随机文章