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

1208. 尽可能使字符串相等

难度中等58

给你两个长度相同的字符串,st

s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。

用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。

如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。

如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0

二分方法


func abs(a int) int {
	if a > 0 {
		return a
	}
	return -a
}

//二分搜索加滑窗
func equalSubstringBinary(s string, t string, maxCost int) int {

	left, right, best := 0, len(s), 0

	for left <= right {

		mid := (left-right)/2 + right
		if judge(s, t, maxCost, mid) {
			best, left = mid, mid+1
		} else {
			right = mid - 1
		}
	}

	return best

}

func judge(s string, t string, maxCost int, winLen int) bool {

	winSum := 0
	for i := 0; i < winLen; i++ {
		winSum += abs(int(s[i]) - int(t[i]))
	}

	if winSum <= maxCost {
		return true
	}

	for i := winLen; i < len(s); i++ {
		winSum -= abs(int(s[i-winLen]) - int(t[i-winLen]))
		winSum += abs(int(s[i]) - int(t[i]))
		if winSum <= maxCost {
			return true
		}

	}
	return false
}

直接滑窗

//纯滑窗
func equalSubstring(s string, t string, maxCost int) int {

	tmpCost, maxLen := 0, 0
	beg, end := 0, 0 //左闭,右开区间
	//注意这里 条件是 beg<= end,beg也可以等于end,意味着从新开始新的区间. 例如s和t中相应字符的差值 都大于 maxCost 的情况
	for beg <= end && end < len(s) {

		if tmpCost <= maxCost { //当前窗口可以满足预算
			if end-beg > maxLen {
				maxLen = end - beg
			}
			//然后追加 end
			delTa := abs(int(s[end]) - int(t[end]))
			tmpCost += delTa
			end++
			continue
		}

		//去掉beg
		delTa := abs(int(s[beg]) - int(t[beg]))
		tmpCost -= delTa
		beg++

	}

	//这里不能漏掉,要再次判断下
	if tmpCost <= maxCost && (end-beg) > maxLen {
		maxLen = end - beg
	}
	return maxLen

}

func abs(a int) int {
	if a > 0 {
		return a
	}
	return -a
}