最小替换子串长度
解题思路
-
统计字符频次:首先统计字符串中 'A'、'S'、'D'、'F' 四个字符的频次。
-
目标频次:计算每个字符的目标频次,即字符串长度除以4。
-
检查是否已经平衡:如果所有字符的频次已经等于目标频次,则不需要替换,返回0。
-
滑动窗口法:使用滑动窗口法,尝试找到最小子串,使得替换该子串后,字符串中 'A'、'S'、'D'、'F' 的频次相等。
- 初始化窗口:设置左右指针,初始窗口大小为1。
- 扩展窗口:右移右指针,扩大窗口,直到窗口内的字符频次满足条件。
- 收缩窗口:右移左指针,缩小窗口,直到窗口内的字符频次不再满足条件。
- 记录最小长度:在每次窗口满足条件时,记录当前窗口的长度,并更新最小长度。
代码解析:
-
初始化:
n = len(input):获取输入字符串的长度。target = n // 4:计算目标频次,即每个字符应该出现的次数。freq = {'A': 0, 'S': 0, 'D': 0, 'F': 0}:初始化一个字典来统计每个字符的频次。
-
统计频次:
- 遍历输入字符串,更新每个字符的频次。
-
检查是否已经平衡:
- 如果所有字符的频次都等于目标频次,则直接返回0。
-
尝试每个可能的长度:
- 对于每个可能的子串长度(从1到n),遍历每个可能的起始位置。
- 计算替换该子串后的频次,并检查是否可以通过添加
length个字符达到平衡。 - 如果可以通过,则返回该子串的长度。
-
返回结果:
- 如果没有找到合适的子串,则返回字符串的总长度。
测试用例:
solution("ADDF") == 1:Truesolution("ASAFASAFADDD") == 3:Truesolution("SSDDFFFFAAAS") == 1:Truesolution("AAAASSSSDDDDFFFF") == 0:Truesolution("AAAADDDDAAAASSSS") == 4:True
代码逻辑:
- 代码首先统计输入字符串中每个字符的频次。
- 然后检查是否已经平衡,如果已经平衡则直接返回0。
- 如果没有平衡,则尝试每个可能的子串长度,检查是否可以通过替换该子串中的字符达到平衡。
- 如果找到合适的子串长度,则返回该长度;否则返回字符串的总长度。
引用证据:
- 代码的逻辑和实现方式与1中的描述一致,即通过遍历所有可能的子串长度来找到最短的平衡子串。
- 3中也提到了类似的逻辑,即通过计算替换后的频次来判断是否可以达到平衡。
n = len(input)
target = n // 4 # 目标频次
# 统计频次
freq = {'A': 0, 'S': 0, 'D': 0, 'F': 0}
for c in input:
freq[c] += 1
# 已经平衡
if all(f == target for f in freq.values()):
return 0
# 尝试每个可能的长度
for length in range(1, n + 1):
# 检查每个起始位置
for start in range(n - length + 1):
# 计算替换该子串后的频次
temp = freq.copy()
for i in range(start, start + length):
temp[input[i]] -= 1
# 检查是否可以通过添加length个字符达到平衡
max_count = max(temp.values())
min_count = min(temp.values())
if max_count - min_count <= length:
# 检查是否可以分配length个字符来达到平衡
needed = sum(max(0, target - count) for count in temp.values())
if needed <= length:
return length
return n
if __name__ == "__main__":
# 测试用例
print(solution("ADDF") == 1) # True
print(solution("ASAFASAFADDD") == 3) # True
print(solution("SSDDFFFFAAAS") == 1) # True
print(solution("AAAASSSSDDDDFFFF") == 0) # True
print(solution("AAAADDDDAAAASSSS") == 4) # True