0187.重复的DNA序列

方法一:哈希表

朴素解法,用哈希表保存所有长度为 10 的子序列出现的次数,当子序列出现次数大于 1 时,把该子序列作为结果之一。

假设字符串 s 长度为 n,则时间复杂度 $O(n \times 10)$,空间复杂度 $O(n)$。

func findRepeatedDnaSequences(s string) []string {
	ans, cnt := []string{}, map[string]int{}
	for i := 0; i <= len(s)-10; i++ {
		sub := s[i : i+10]
		cnt[sub]++
		if cnt[sub] == 2 {
			ans = append(ans, sub)
		}
	}
	return ans
}

方法二:Rabin-Karp 字符串匹配算法

0028.找出字符串中第一个匹配项的下标类似,本题可以借助哈希函数将子序列计数的时间复杂度降低到 $O(1)$。

假设字符串 s 长度为 n,则时间复杂度为 $O(n)$,空间复杂度 $O(n)$。

func findRepeatedDnaSequences(s string) []string {
	hashCode := map[byte]int{'A': 0, 'C': 1, 'G': 2, 'T': 3}
	ans, cnt, left, right := []string{}, map[int]int{}, 0, 0

	sha, multi := 0, int(math.Pow(4, 9))
	for ; right < len(s); right++ {
		sha = sha*4 + hashCode[s[right]]
		if right-left+1 < 10 {
			continue
		}
		cnt[sha]++
		if cnt[sha] == 2 {
			ans = append(ans, s[left:right+1])
		}
		sha, left = sha-multi*hashCode[s[left]], left+1
	}
	return ans
}