424.替换后的最长重复字符

88 阅读1分钟

题目:
给你一个字符串 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
}