最小子串替换问题 - 详细解析
问题描述
给定一个只包含字符 A、S、D、F 的字符串,要求通过最少的替换操作,使得这四个字符在字符串中的出现频率相等。要求求出满足这一条件的最小子串长度。
解决思路
-
目标频次计算:
- 由于字符串的长度是 4 的倍数,因此可以计算出每个字符的目标频次。目标频次为
len(input) // 4,即每个字符应出现的频次。
- 由于字符串的长度是 4 的倍数,因此可以计算出每个字符的目标频次。目标频次为
-
字符频次统计:
- 使用
Counter来统计字符串中每个字符的出现次数,找出哪些字符频次过高或过低。
- 使用
-
滑动窗口策略:
- 我们的目标是找到一个最小子串,使得通过对其进行替换,所有字符的频次能够达到目标频次。采用滑动窗口的方式可以高效地计算出这个最小子串。
滑动窗口的工作原理:
- 通过动态调整窗口的左右边界,维护窗口内字符的频次。在每次扩展右边界时,我们更新窗口内的字符频次,并检查是否满足替换条件。如果满足条件,收缩左边界,尝试更新最小窗口的大小。
实现步骤
- 统计字符频次:使用
Counter来统计字符串中每个字符的出现次数。 - 计算目标频次:每个字符应有的目标频次为
len(input) // 4。 - 计算需要替换的字符:如果某个字符的频次大于目标频次,则需要进行替换。
- 滑动窗口:通过滑动窗口动态调整窗口内的字符频次,检查是否满足替换条件,并记录最小窗口长度。
代码解析
def solution(input):
from collections import Counter
# 统计字符频次
count = Counter(input)
# 计算目标频次
target_count = len(input) // 4
# 计算需要替换的字符
need_replace = {}
for char in 'ASDF':
if count[char] > target_count:
need_replace[char] = count[char] - target_count
# 如果没有需要替换的字符,直接返回0
if not need_replace:
return 0
# 滑动窗口
left = 0
min_length = len(input)
window_count = Counter()
for right in range(len(input)):
# 更新窗口内的字符频次
window_count[input[right]] += 1
# 检查窗口是否满足替换条件
while all(window_count[char] >= need_replace.get(char, 0) for char in 'ASDF'):
# 更新最小长度
min_length = min(min_length, right - left + 1)
# 移动左指针
window_count[input[left]] -= 1
left += 1
return min_length
代码详解
-
字符频次统计:
count = Counter(input)这行代码使用
Counter统计输入字符串input中每个字符的频次。 -
计算目标频次:
target_count = len(input) // 4由于字符串长度总是 4 的倍数,目标频次是字符串长度除以 4。
-
计算需要替换的字符:
need_replace = {} for char in 'ASDF': if count[char] > target_count: need_replace[char] = count[char] - target_count通过遍历字符集
'ASDF',找到哪些字符频次过高,并记录下需要替换的字符及其多余的数量。 -
滑动窗口处理:
window_count = Counter() left = 0 min_length = len(input) for right in range(len(input)): window_count[input[right]] += 1 while all(window_count[char] >= need_replace.get(char, 0) for char in 'ASDF'): min_length = min(min_length, right - left + 1) window_count[input[left]] -= 1 left += 1- 右边界扩展:通过增加右边界来扩展窗口,并更新窗口内字符的频次。
- 左边界收缩:当窗口内字符频次满足替换条件时,收缩左边界,并尝试找到最小子串。
-
返回最小窗口长度:
return min_length最后返回符合条件的最小窗口长度。
时间复杂度与空间复杂度
- 时间复杂度:
O(n),其中n为字符串的长度。右边界遍历一次字符串,左边界仅在窗口满足条件时收缩一次,因此时间复杂度为线性。 - 空间复杂度:
O(1),使用的额外空间是固定的,主要用于存储字符频次和窗口内的频次信息,字符集大小固定为 4,因此空间复杂度为常数。
总结
通过滑动窗口技术结合字符频次管理,可以高效地求解最小子串替换问题。该方法避免了暴力枚举所有子串,从而优化了时间复杂度,且能在常量空间内进行高效求解。