题目地址:
https://leetcode.com/problems/repeated-dna-sequences/
给定一个长 n n n的字符串 s s s,问其长度为 10 10 10的子串中重复多于 1 1 1次的有哪些。
法1:哈希表。直接把每个长度为 10 10 10的字符串的count记下来,然后看计数大于 1 1 1的子串有哪些。代码如下:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Solution {
public List<String> findRepeatedDnaSequences(String s) {
Map<String, Integer> map = new HashMap<>();
for (int i = 0; i <= s.length() - 10; i++) {
String sub = s.substring(i, i + 10);
map.put(sub, map.getOrDefault(sub, 0) + 1);
}
List<String> res = new ArrayList<>();
for (Map.Entry<String, Integer> entry : map.entrySet()) {
if (entry.getValue() > 1) {
res.add(entry.getKey());
}
}
return res;
}
}
时空复杂度 O ( n ) O(n) O(n)。
法2:字符串哈希。把每个长度为 10 10 10的子串的哈希值求出来,这样可以提高判重的效率(判重的效率由判两个字符串相等变成了判两个整数相等,显然判整数相等效率更高)。代码如下:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Solution2 {
public List<String> findRepeatedDnaSequences(String s) {
if (s.length() < 10) {
return new ArrayList<>();
}
Set<String> res = new HashSet<>();
Set<Long> set = new HashSet<>();
long hash = 0, pow = 1, p = 131;
// 把s[0:9]的哈希值存入set
for (int i = 0; i < 10; i++) {
hash = hash * p + s.charAt(i);
pow *= p;
}
set.add(hash);
for (int i = 10; i < s.length(); i++) {
// 算出s[i-9:i]的哈希值
hash = hash * p + s.charAt(i);
hash -= pow * s.charAt(i - 10);
// 发现出现多于1次了,则加入答案
if (set.contains(hash)) {
res.add(s.substring(i - 9, i + 1));
} else {
set.add(hash);
}
}
return new ArrayList<>(res);
}
}
时空复杂度 O ( n ) O(n) O(n)。