leetcode-cn 2021年1月 2021年2月 每日一题

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

难度中等258

给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

**注意:**字符串长度 和 k 不会超过 104。


/*
424. 替换后的最长重复字符
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意:字符串长度 和 k 不会超过 104。
1. 二分法,每次定义最长的重复字符长度 winLen
2. 通过滑窗判断是否可以满足 ; 计算滑窗内各个字符的个数,然后得到频率最大的字符个数 cnt, 判断 cnt+k>= winLen ,就返回true
*/

/*
424. 替换后的最长重复字符
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意:字符串长度 和 k 不会超过 104。
1. 二分法,每次定义最长的重复字符长度 winLen
2. 通过滑窗判断是否可以满足 ; 计算滑窗内各个字符的个数,然后得到频率最大的字符个数 cnt, 判断 cnt+k>= winLen ,就返回true
*/
func characterReplacement(s string, k int) int {
	if len(s) == 0 || k >= len(s)-1 {
		return len(s)
	}

	sb := []byte(s)
	start := k
	best := -1
	end := len(s)
	for start <= end {
		mid := (end-start)/2 + start
		if judge(sb, mid, k) {
			best, start = mid, mid+1
		} else {
			end = mid - 1
		}
	}

	return best

}

func judge(s []byte, winEnd, k int) bool {

	charCnt := make([]int, 26)
	for i := 0; i < winEnd; i++ {
		charCnt[s[i]-'A']++
	}

	if windowCanfill(charCnt, winEnd, k) {
		return true
	}

	for i := winEnd; i < len(s); i++ {
		charCnt[s[i]-'A']++
		charCnt[s[i-winEnd]-'A']--
		if windowCanfill(charCnt, winEnd, k) {
			return true
		}

	}

	return false

}

/*
1. 求窗口内频率最高的字符 c
2. 把窗口内c之外的字符个数如果小于等于k,那么就可以把其他的字符都换为c
*/
func windowCanfill(charCnt []int, winEnd, k int) bool {

	maxCnt := 0
	for _, v := range charCnt {
		if v > maxCnt {
			maxCnt = v
		}
	}
	if maxCnt+k >= winEnd {
		return true
	}
	return false
}