Go猜想录
大道至简,悟者天成
同向双指针(下)

摘要

  • 数组和字符串上的同向双指针
    • 滑动窗口求和
    • K次替换后最长的重复字符子串
  • 快慢指针算法
    • 链表求交、链表求环
    • 链表中位点

604 · 滑动窗口内数的和

nums = [1,2,7,8,5], k = 3
求出数组中所有连续 k 个数之和
返回 [10,17,20]

func WinSum(nums []int, k int) []int {
	res := []int{}
	if len(nums) == 0 || len(nums) < k {
		return res
	}

	j := 0
	windowSum := 0
	for i := 0; i < len(nums); i++ {
		for j < len(nums) && j-i < k {
			windowSum += nums[j]
			j++
		}
		if j-i == k {
			res = append(res, windowSum)
		}
		windowSum -= nums[i]
	}
	return res
}

1246 · 替换后的最长重复字符

允许替换字符串中的字符 K 次
问替换之后,最长的重复字符有多长
s = ABABA, k = 2
替换 B 到 A 可以获得长度为 5 的全 A 子串

/**
 * @param s: a string
 * @param k: a integer
 * @return: return a integer
 */
func CharacterReplacement(s string, k int) int {
	counter := make(map[byte]int)
	ans := 0
	// j 指向满足条件的子字符串的后面一个位置
	j := 0
	maxFreq := 0
	for i := 0; i < len(s); i++ {
		// 找到 i ~ j-1 这一段是最长的以i开头的满足
		// 不超过 k 次替换的 substring
		for j < len(s) && j-i-maxFreq <= k {
			counter[s[j]]++
			maxFreq = max(maxFreq, counter[s[j]])
			j++
		}

		if j-i-maxFreq > k {
			// i ~ j-1 的 substring 需要 k+1
			// i ~ j-2 的 substring 只需要 k 次替换
			ans = max(ans, j-2-i+1)
		} else {
			ans = max(ans, j-i)
		}

		counter[s[i]]--
		maxFreq = 0
		for _, cnt := range counter {
			if cnt > maxFreq {
				maxFreq = cnt
			}
		}
	}
	return ans
}

数组和字符串上的同向双指针总结

数组和字符串的问题有很多题都是和双指针,特别是同向双指针有关
通常问题让我们求是一段子数组或者子字符串
所以遇到“子数组 SubArray” 和“子字符串 SubString” 就需要往同向双指针思考


知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。