题目:
给你一个字符串 s 和一个整数 k 。你可以选择字符串中的任一字符,并将其更改为任何其他大写英文字符。该操作最多可执行 k 次。
在执行上述操作后,返回包含相同字母的最长子字符串的长度。
算法:
方法一:滑动窗口
两个指针start,end。cur记录当前的字符。end右移,遇到不等于cur的字符k--。
当k==0并且cur != s[end]时,计算ans = max(ans, end-start)。
然后将start右移,直到遇到s[start] != cur 释放一个k。然后end可以继续右移。
func characterReplacement(s string, k int) int {
ans := 0
count := make([]int, 26)
n := len(s)
for left, right := 0, 0; right < n; right ++ {
count[int(s[right] - 'A')] ++
for !check(count, k) {
count[int(s[left] - 'A')] --
left ++
}
ans = max(ans, right - left + 1)
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
// check函数,如何判断窗口内字符串翻转能满足条件是关键
// 翻转次数小于等于k即可,翻转次数=总的字符串个数-最多的字符串个数
// 可以翻转sum - maxCount个数,反转个数小于等于k则说明这个count的长度是有效的长度。
func check(count []int, k int) bool {
sum, maxCount := 0, 0
for i := range count {
sum = sum + count[i]
maxCount = max(maxCount, count[i])
}
return sum - maxCount <= k
}
方法二:滑动窗口
思路和方法一是一样的,注意
1.slideMaxCharCount记录的是滑动窗口内,历史重复次数最多的字符个数。
2.count数组记录滑动窗口内重复次数最多的字符个数,left右移时会减少。
3.如果slideMaxCharCount + k长度的字符串可以翻转k个字符满足条件,则我们不必要考虑比right - left + 1 比slideMaxCharCount + k更小的窗口长度。不妨记录slide中出现过重复字符次数最多的值slideMaxCharCount,只有count[int(s[right] - 'A')] ++使得 slideMaxCharCount增加时,窗口才会扩容。
果然不明白代码的时候还是得debug跑一跑。
func characterReplacement(s string, k int) int {
count := make([]int, 26)
n := len(s)
slideMaxCharCount := 0
left, right := 0, 0
for ; right < n; right ++ {
count[int(s[right] - 'A')] ++
slideMaxCharCount = max(slideMaxCharCount, count[int(s[right] - 'A')])
// historyMaxCount + k都无法满足这个滑动窗口,滑动窗口收缩
for right - left + 1 > slideMaxCharCount + k {
count[int(s[left] - 'A')] --
left ++
}
}
return right - left
}
func max(a, b int) int {
if a > b {
return a
}
return b
}