问题描述
小R有一个由小写字母组成的字符串 str1,长度为 n。字符串中有些位置的字符可以通过修复操作来修改为 a-z 中的任意一个字母,这个修复操作最多可以进行 m 次。现在,小R想知道,经过最多 m 次修复操作后,字符串中由相同字符组成的最长连续子串的最大长度是多少。
注意,str2表示哪些下标可以修改,如果为1那么就可以修改,如果为0那么就不行。
测试样例
样例1:
输入:n = 5, m = 2, str1 = "abcda", str2 = "01110"
输出:3
样例2:
输入:n = 7, m = 2, str1 = "abbaccb", str2 = "1001001"
输出:4
样例3:
输入:n = 3, m = 0, str1 = "aab", str2 = "101"
输出:2
解题思路
考虑将每个字母 'a' 到 'z' 作为可能的目标字符。对于每个目标字符,使用滑动窗口的方法,找出最长的连续子串,使得在不超过 m 次修复操作的情况下,可以将其他字符(通过修复操作)转换为目标字符。
算法流程
遍历每个可能的目标字符
将所有的字符都替换成某一个目标字符 'a' 到 'z',然后找出对该目标字符修复的最长连续子串。
滑动窗口
对于每一个目标字符,使用滑动窗口维护一个子串。窗口的左右边界由 left 和 right 变量表示。遍历字符串时,如果当前位置字符与目标字符不同且该位置可以修复(即 str2[right] == '1'),则增加修复操作计数。如果超过了最大允许修复次数 m,则将左边界 left 向右移动,直到修复次数不超过 m。
记录最大长度
每次调整窗口时,计算当前窗口的长度,并更新最大长度。最后,遍历所有可能的目标字符,找到最大长度。
代码实现
def solution(n, m, str1, str2):
max_length = 0 # 用于记录最终的最大长度
# 遍历所有可能的目标字符
for target_char in 'abcdefghijklmnopqrstuvwxyz':
left = 0 # 滑动窗口的左边界
count = 0 # 当前窗口内需要进行的修复操作次数
for right in range(n):
# 当前字符是否与目标字符相同
if str1[right] != target_char:
if str2[right] == '1':
count += 1 # 需要进行一次修复操作
else:
# 当前位置无法修改,需要重置窗口
left = right + 1
count = 0
continue # 跳过当前字符,开始新的窗口
# 如果修复操作次数超过 m,移动左边界
while count > m:
if str1[left] != target_char and str2[left] == '1':
count -= 1 # 减少一次修复操作
left += 1 # 移动左边界
# 更新当前窗口的长度
current_length = right - left + 1
if current_length > max_length:
max_length = current_length
return max_length
if __name__ == "__main__":
print(solution(5, 2, "abcda", "01110") == 3)
print(solution(7, 2, "abbaccb", "1001001") == 4)
print(solution(3, 0, "aab", "101") == 2)
总结
滑动窗口的技巧在字符串问题中非常常见,可以高效地解决类似的子串问题,尤其适合处理子串修复、删除或者替换等变动情况。