最小替换子串长度问题 | 豆包MarsCode AI刷题
问题描述
小F得到了一个特殊的字符串,这个字符串只包含字符 A、S、D、F,且其长度总是 4 的倍数。他的任务是通过尽可能少的替换,使得 A、S、D、F 这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。
测试样例
- 输入:
"ADDF"→ 输出:1 - 输入:
"ASAFASAFADDD"→ 输出:3 - 输入:
"SSDDFFFFAAAS"→ 输出:1 - 输入:
"AAAASSSSDDDDFFFF"→ 输出:0 - 输入:
"AAAADDDDAAAASSSS"→ 输出:4
算法原理与思路
问题分析
为了达到字符频次的平衡,每个字符 A、S、D、F 应该出现的次数是 target = len(input) / 4。我们要找到一个最小的子串,通过替换这个子串,使得所有字符的频次达到 target。
解题思路
- 统计频次:首先统计输入字符串中每个字符的初始频次。
- 目标检查:如果所有字符的频次已经满足
<= target的条件,直接返回0。 - 滑动窗口:
- 右指针
r逐渐向右扩展,降低窗口内字符的频次。 - 当窗口外的字符频次满足
<= target时,尝试通过左指针l缩小窗口。 - 通过记录窗口大小,找到最小满足条件的子串。
- 右指针
代码实现
Go 语言实现
package main
import "fmt"
// 解决最小替换子串长度问题的函数
func solution(input string) int {
n := len(input)
targetCount := n / 4 // 每个字符应出现的次数
charMap := make(map[byte]int, 4) // 统计每个字符的出现次数
// 初始化 charMap
for i := 0; i < n; i++ {
charMap[input[i]]++
}
// 检查当前频次是否已经满足目标频次
if isBalanced(charMap, targetCount) {
return 0
}
// 使用滑动窗口找到最小的可替换子串
minLen := n
l := 0
for r := 0; r < n; r++ {
charMap[input[r]]-- // 移动右指针,缩小当前字符的频次
// 当满足条件时,尝试缩小窗口
for isBalanced(charMap, targetCount) {
minLen = min(minLen, r-l+1)
charMap[input[l]]++ // 移动左指针,恢复左边界字符的频次
l++
}
}
return minLen
}
// 检查是否满足频次平衡
func isBalanced(charMap map[byte]int, target int) bool {
return charMap['A'] <= target && charMap['S'] <= target && charMap['D'] <= target && charMap['F'] <= target
}
// 返回两个数中的较小值
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
// 测试用例
fmt.Println(solution("ADDF")) // 输出 1
fmt.Println(solution("ASAFASAFADDD")) // 输出 3
}
Python 版本实现
def solution(input: str) -> int:
n = len(input)
target_count = n // 4 # 每个字符应出现的目标频次
char_map = {'A': 0, 'S': 0, 'D': 0, 'F': 0}
# 统计每个字符的初始频次
for char in input:
char_map[char] += 1
# 检查是否已经满足平衡
if is_balanced(char_map, target_count):
return 0
# 滑动窗口寻找最小的可替换子串
min_len = n
l = 0
for r in range(n):
char_map[input[r]] -= 1 # 缩小右边界字符的频次
# 尝试缩小窗口,如果满足条件
while is_balanced(char_map, target_count):
min_len = min(min_len, r - l + 1)
char_map[input[l]] += 1 # 恢复左边界字符的频次
l += 1
return min_len
# 检查是否满足平衡
def is_balanced(char_map, target):
return all(count <= target for count in char_map.values())
# 测试案例
if __name__ == "__main__":
print(solution("ADDF")) # 输出 1
print(solution("ASAFASAFADDD")) # 输出 3
复杂度分析
- 时间复杂度:
O(n),因为滑动窗口内的左右指针各遍历每个字符最多一次。 - 空间复杂度:
O(1),只需要常数大小的空间来存储字符频次。