问题描述
小F得到了一个特殊的字符串,这个字符串只包含字符A、S、D、F,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得A、S、D、F这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
测试样例
样例1:
输入:
input = "ADDF"
输出:1
样例2:
输入:
input = "ASAFASAFADDD"
输出:3
样例3:
输入:
input = "SSDDFFFFAAAS"
输出:1
样例4:
输入:
input = "AAAASSSSDDDDFFFF"
输出:0
样例5:
输入:
input = "AAAADDDDAAAASSSS"
输出:4
解题方法:滑动窗口
滑动窗口是一种双指针技巧,通过动态维护一个区间(窗口),用来高效地解决一类与区间或子数组有关的问题。其特点是:
- 窗口定义:一个连续子数组或子串。
- 指针移动:通常用两个指针
left和right分别表示窗口的起点和终点,动态调整这两个指针的值以扩大或缩小窗口。 - 适用场景:在子数组或子串问题中,需要动态检查一个区间是否满足某些条件,并且在满足条件时更新结果。
为什么滑动窗口可以应用于此题
-
问题性质:
- 本题要求找到一个最小的子串,使得移除该子串后,剩下的字符频次达到平衡(每种字符出现次数小于或等于
n // 4)。 - 我们可以通过滑动窗口动态维护一个候选子串
[left, right],并在满足条件时更新结果。
- 本题要求找到一个最小的子串,使得移除该子串后,剩下的字符频次达到平衡(每种字符出现次数小于或等于
-
滑动窗口在本题的作用:
- 扩大窗口:通过移动右指针
right增加窗口的长度,尝试找到包含更多不需要字符的子串。 - 收缩窗口:当移除窗口后剩余字符频次满足平衡条件时,通过移动左指针
left收缩窗口,找到可能的更小子串。
- 扩大窗口:通过移动右指针
算法步骤
1. 初始化
- 计算字符串长度
n。 - 计算每种字符的目标频次
target = n // 4。 - 统计整个字符串中每种字符的频次,存储在字典
freq中。
2. 快速检查是否已经平衡
- 如果每种字符的频次都已经小于或等于
target,说明字符串无需任何替换,直接返回结果0。
3. 初始化滑动窗口变量
- 定义两个指针
left和right,分别表示窗口的左边界和右边界。 - 定义
min_length,用于记录满足条件的最小子串长度,初始值为 n。
4. 移动右指针
- 使用
right遍历整个字符串,表示动态扩大窗口的右边界。 - 每次移动右指针时,模拟移除窗口内的字符,将
freq[input[right]]减去 1。
5. 检查平衡条件
-
在每次右指针更新后,检查剩余的字符频次是否满足条件,即所有字符的频次都小于或等于
target。while all(f <= target for f in freq.values()):
6. 缩小窗口(左指针移动)
-
如果满足平衡条件,说明当前窗口是一个有效的候选子串。
-
更新最小子串长度:
- 计算当前窗口长度为
right - left + 1,并更新min_length。
- 计算当前窗口长度为
-
尝试缩小窗口:
- 将左指针的字符重新加入到
freq中(频次加 1)。 - 移动左指针
left,缩小窗口。
- 将左指针的字符重新加入到
7. 返回结果
- 当右指针遍历结束后,返回记录的
min_length,即满足条件的最小子串长度。
代码
def solution(input):
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
# 滑动窗口
left = 0
min_length = n # 初始化为字符串长度
for right in range(n):
# 移动右指针,减去当前字符的频次
freq[input[right]] -= 1
# 检查是否满足平衡条件
while all(f <= target for f in freq.values()):
# 更新最小长度
min_length = min(min_length, right - left + 1)
# 收缩窗口:移动左指针
freq[input[left]] += 1
left += 1
return min_length
if __name__ == "__main__":
# You can add more test cases here
print(solution("ADDF") == 1 )
print(solution("ASAFASAFADDD") == 3)