给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
注意:
字符串长度 和 k 不会超过 104。
示例 1:
输入: s = "ABAB", k = 2 输出: 4 解释: 用两个'A'替换为两个'B',反之亦然。
示例 2:
输入: s = "AABABBA", k = 1 输出: 4 解释: 将中间的一个'A'替换为'B',字符串变为 "AABBBBA"。 子串 "BBBB" 有最长重复字母, 答案为 4。
最开始考虑“中心扩散法”。
选定了一个字符s[i]然后指针右移保存最长子串范围和剩余的k。右移时k只要大于0便可以跳过不相同的字符,然后k-=1.
然后分别向两边扩展直到k为0.
很遗憾还有更好的办法,自我刷leetcode以来仅仅见过不超过三次的办法——滑动窗口。
以示例2为例。
选定窗口长度w=2,因为k=1,所以长度<=1的任何子串都可以被换成指定的字符。
统计一个窗口的子串中各个字符的数量,可以用哈希表,也可以用数组。
最后在这个统计数据结构中找到最多的那个,设为n。
如果w-n<=k说明剩下的可以被替换为最多的那个字符,我们把窗口进一步扩大,
否则缩小窗口。
值得一说的是滑动窗口的经典技巧:
比如原来是s【0-3】={A:3,B:1},那么扩大到s【0-4】(宽度为5)时,只需递增新加入的字符={A:3,B:2},
向前缩小时,同样的,递减除去的字符数量即可。
代码如下:
class Solution:
def find_max(self,arr):
j,val=-1,-1
for i,v in enumerate(arr):
if v>val:
val=v
j=i
return j
def characterReplacement(self, s, k):
if s=='':
return 0
arr=[0 for _ in range(26)]
orda=ord('A')
width=k+1
i=0
max_len=k
for c in s[:width]:
arr[ord(c)-orda]+=1
while True:
j=self.find_max(arr)
if width-arr[j]<=k:
max_len=max(max_len,width)
if i+width<len(s):
arr[ord(s[i+width])-orda]+=1
width+=1
else:
break
else:
arr[ord(s[i])-orda]-=1
i+=1
width-=1
return max_len
其中find_max是个辅助函数,为了找到数据结构里数量最多的字符。