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
}
, multiple selections available,
Related content
Week 3 @ 2025 算法周记【前缀和 + 双指针数组】
Week 3 @ 2025 算法周记【前缀和 + 双指针数组】
More like this
Week 6 @ 2025 算法周记【前缀和 + 滑动窗口】
Week 6 @ 2025 算法周记【前缀和 + 滑动窗口】
More like this
Week 45 @ 2024 算法周记【动态规划+回溯】
Week 45 @ 2024 算法周记【动态规划+回溯】
More like this
Week 8 @ 2025 算法周记【滑动窗口 + 前缀和】
Week 8 @ 2025 算法周记【滑动窗口 + 前缀和】
More like this
Week 44 @ 2024 算法周记【二分查找】
Week 44 @ 2024 算法周记【二分查找】
More like this
Week 51 @ 2024 算法周记【双指针链表+丑数】
Week 51 @ 2024 算法周记【双指针链表+丑数】
More like this