问题描述
小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
思考
给定一个字符串 str1
,长度为 n
,我们可以最多进行 m
次修改操作,把字符串中的某些字符修改为任意字母。哪些位置可以修改由字符串 str2
指定,其中 '1' 表示该位置可以修改,'0' 表示该位置不能修改。我们需要找出在最多 m
次修改操作后,字符串中由相同字符组成的最长连续子串的最大长度。
解决思路
我们需要针对每个可能的字符(从 'a' 到 'z')进行尝试,看看能否通过修改操作使其形成最长的连续子串。具体步骤如下:
-
初始化变量:
max_len
用于记录最终的最大长度。left
表示滑动窗口的左边界。count
用于记录当前窗口中需要修改的字符数量。
-
遍历每个字符
c
:- 我们假设当前要将整个窗口中的字符都变成字符
c
。
- 我们假设当前要将整个窗口中的字符都变成字符
-
使用滑动窗口法:
-
right
指针从左到右遍历字符串。 -
如果
str1[right]
不是字符c
,我们检查str2[right]
:- 如果
str2[right] == '1'
,表示可以修改此处的字符,增加count
。 - 如果
str2[right] == '0'
,表示不能修改,重置窗口,把left
移动到right + 1
,并重置count
。
- 如果
-
-
调整窗口:
- 如果
count
超过m
,意味着修改次数超过限制,需要通过移动left
来缩小窗口,同时减少count
。
- 如果
-
更新最大长度:
- 在每一步中计算当前窗口长度
window_len = right - left + 1
,如果window_len
大于current_max
,则更新current_max
。 - 如果
current_max
大于max_len
,则更新max_len
。
- 在每一步中计算当前窗口长度
-
返回结果:
- 遍历所有字符后,返回
max_len
作为最终结果。
- 遍历所有字符后,返回
注意事项
- 边界条件: 需要注意当滑动窗口的左边界
left
需要更新时,count
也要相应减少。 - 性能考虑: 虽然代码需要针对每个字符都进行一次完整的遍历,但这种方法保证了在每个字符的情况下都能找到可能的最长长度。
复杂度分析
- 时间复杂度: 对于每个字符(26个字母),我们用滑动窗口方法遍历整个字符串一次,时间复杂度为
O(n)
。因此总的时间复杂度为O(26 * n)
,即O(n)
,因为常数因子26可以忽略。 - 空间复杂度: 只使用了常数空间来存储变量,因此空间复杂度为
O(1)
。
Solution代码
def solution(n, m, str1, str2):
max_len = 0
for c in 'abcdefghijklmnopqrstuvwxyz':
left = 0
count = 0 # 修复次数
current_max = 0
for right in range(n):
if str1[right] != c:
if str2[right] == '1':
count += 1
else:
# 无法修改,重置窗口
left = right + 1
count = 0
continue
# 当修复次数超过m时,移动左指针
while count > m:
if str1[left] != c and str2[left] == '1':
count -= 1
left += 1
# 更新当前最大长度
window_len = right - left + 1
if window_len > current_max:
current_max = window_len
if current_max > max_len:
max_len = current_max
return max_len
```