问题描述
小R得到了一个由大写字母组成的字符串,长度为 n。她可以对字符串中的字符进行修改,每次操作允许将某个位置的字符修改为任意字符。例如,字符串 ABC 的第一个字符 A 改为 B,则字符串变为 BBC。她最多可以进行 k 次这样的修改。
小R想知道,通过最多 k 次修改后,字符串中由最多两种不同字母组成的最长连续子串的长度是多少。
问题分析
这是一个滑动窗口的问题,我们需要:
- 维护一个窗口,使其最多包含两种不同字母
- 在窗口内最多允许k次修改
- 找到满足条件的最长窗口长度
实现的代码如下:
def solution(n: int, k: int, s: str) -> int:
char_count = {}
for c in s:
char_count[c] = char_count.get(c, 0) + 1
sorted_chars = sorted(char_count.items(), key=lambda x: x[1], reverse=True)
if len(sorted_chars) <= 2:
return n
main_chars = {sorted_chars[0][0], sorted_chars[1][0]}
changes = 0
curr_length = 0
max_length = 0
start = 0
for i in range(n):
if s[i] in main_chars:
curr_length += 1
else:
if changes < k:
changes += 1
curr_length += 1
else:
while start < i and changes >= k:
if s[start] not in main_chars:
changes -= 1
start += 1
curr_length -= 1
if changes < k:
changes += 1
curr_length += 1
max_length = max(max_length, curr_length)
return max_length
豆包检查后提出了两点潜在问题:
- 在滑动窗口的逻辑中,
start指针的移动逻辑可能需要进一步检查。特别是在while start < i and changes >= k循环中,start指针的移动可能会导致窗口长度不正确。 - 具体来说,当
changes >= k时,start指针应该移动到下一个不在main_chars中的字符,而不是简单地移动一个位置。
基于此豆包给出了两点总结建议:
- 滑动窗口的收缩逻辑可能需要进一步优化。
- 建议使用两个指针来更清晰地管理窗口的扩展和收缩。
之后我对代码进行了修改:
def solution(n: int, k: int, s: str) -> int:
if n <= 2:
return n
def get_window_length(c1, c2):
# 计算使用字符c1和c2能获得的最长窗口
left = modifications = 0
max_length = 0
for right in range(n):
# 如果当前字符不是c1或c2,需要修改
if s[right] != c1 and s[right] != c2:
modifications += 1
# 如果修改次数超过限制,移动左窗口
while modifications > k:
if s[left] != c1 and s[left] != c2:
modifications -= 1
left += 1
curr_length = right - left + 1
max_length = max(max_length, curr_length)
return max_length
# 尝试所有可能的两个字母组合
result = 0
letters = set(s)
for c1 in letters:
for c2 in letters:
result = max(result, get_window_length(c1, c2))
return min(n, result)
关键点解析
-
滑动窗口技巧:
- 使用左右指针维护窗口
- 动态调整窗口大小以满足条件
-
修改策略:
- 优先考虑必要的修改
- 合理利用剩余的修改次数
-
优化思路:
- 枚举可能的两个字母组合
- 对每种组合计算最长可能长度
总结
这道题的解决过程展示了如何将复杂问题分解为可管理的子问题,以及如何通过不同的思路来优化解决方案。滑动窗口配合状态维护的思路在类似的字符串处理问题中非常有用。