Week 7 @ 2025 算法周记【Rabin-Karp 字符匹配 + 前缀和】

Rabin-Karp 字符匹配算法

LC 187. Repeated DNA Sequences 重复的 DNA 序列

https://leetcode.com/problems/repeated-dna-sequences/description/

暴力解法

func findRepeatedDnaSequences(s string) []string { var result []string exists := make(map[string]int, len(s)) for i := 0; i <= len(s)-10; i++ { ss := s[i:i+10] exists[ss]++ if exists[ss] == 2 { result = append(result, ss) } } return result }

滑动哈希

func findRepeatedDnaSequences(s string) []string { var result []string exists := make(map[int]int, len(s)) v := 0 left, right := 0, 0 for right < len(s) { v = v * 4 + getV(s[right]) right++ if right - left == 10 { exists[v]++ if exists[v] == 2 { result = append(result, s[left:right]) } v -= getV(s[left]) * 262144 // 4^9 left++ } } return result } func getV(c byte) int { switch c { case 'A': return 0 case 'C': return 1 case 'G': return 2 case 'T': return 3 default: panic("unknown") } }

前缀和+哈希表

LC 525. Contiguous Array 连续数组

https://leetcode.com/problems/contiguous-array/

func findMaxLength(nums []int) int { preSum := make([]int, len(nums)) preSum[0] = transform(nums[0]) for i := 1; i < len(nums); i++ { preSum[i] = preSum[i-1] + transform(nums[i]) } // fmt.Println(preSum) preSumMap := make(map[int]int, len(preSum)) for i, v := range preSum { preSumMap[v] = i } maxL := 0 for i, v := range preSum { if v == 0 { maxL = max(maxL, i+1) } } for i, v := range preSum { j, exists := preSumMap[v] if exists { maxL = max(maxL, abs(i - j)) } } return maxL } func transform(v int) int { if v == 0 { return -1 } else { return 1 } } func abs(v int) int { if v < 0 { return -v } else { return v } }

进一步优化前缀和(1-based index)

func findMaxLength(nums []int) int { preSum := make([]int, len(nums)+1) for i := range nums { preSum[i+1] = preSum[i] + transform(nums[i]) } // fmt.Println(preSum) preSumMap := make(map[int]int, len(preSum)) for i, v := range preSum { preSumMap[v] = i } maxL := 0 for i, v := range preSum { j, exists := preSumMap[v] if exists { maxL = max(maxL, abs(i - j)) } } return maxL } func transform(v int) int { if v == 0 { return -1 } else { return 1 } } func abs(v int) int { if v < 0 { return -v } else { return v } }

LC 523. 连续的子数组和

https://leetcode.com/problems/continuous-subarray-sum/

func checkSubarraySum(nums []int, k int) bool { preSum := make([]int, len(nums) + 1) for i := range nums { preSum[i+1] = (preSum[i] + nums[i]) % k } preSumMap := make(map[int]int, len(nums)+1) for i, v := range preSum { preSumMap[v] = i } for i, v := range preSum { j, exists := preSumMap[v] if exists && j - i >= 2 { return true } } return false }

LC 560. 和为 K 的子数组

https://leetcode.com/problems/subarray-sum-equals-k/

func subarraySum(nums []int, k int) int { preSum := make([]int, len(nums)+1) for i, v := range nums { preSum[i+1] = preSum[i] + v } mm := make(map[int][]int, len(preSum)) for i, v := range preSum { mm[v] = append(mm[v], i) } count := 0 for i, v := range preSum { js, exists := mm[v + k] if exists { for _, j := range js { if j > i { count++ } } } } return count }

简化

func subarraySum(nums []int, k int) int { preSum := 0 count := make(map[int]int, len(nums)+1) count[0] = 1 result := 0 for _, v := range nums { preSum += v need := preSum - k result += count[need] count[preSum]++ } return result }

Related content