-
题目:
所有 DNA 都由一系列缩写为 'A','C','G' 和 'T' 的核苷酸组成,例如:"ACGAATTCCG"。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。 编写一个函数来找出所有目标子串,目标子串的长度为 10,且在 DNA 字符串 s 中出现次数超过一次。
-
示例 1:
输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 输出:["AAAAACCCCC","CCCCCAAAAA"]
-
示例 2:
输入:s = "AAAAAAAAAAAAA" 输出:["AAAAAAAAAA"]
-
提示
- 0 <= s.length <= 105
s[i]
为'A'
、'C'
、'G'
或'T'
思路 :
- 方案一:滑动窗口。(s.substring实现是new一个String,频繁创建对象需耗费较多的内存)
- 方案二:位运算+滑动窗口。总共就四个字母,两个字节就可以存下,并且总长度为10故int类型就可以存下是个字符。为了避免频繁创建对象,将10个字符转为int类型。当这个int值出现两次时再创建对象。(猜测会比方法一更省空间和时间)
示例一:
class Solution {
public List<String> findRepeatedDnaSequences(String s) {
if (s.length() < 10) {
return Collections.emptyList();
}
Set<String> resultSet = new HashSet<>();
Set<String> set = new HashSet<>();
char[] chars = s.toCharArray();
for (int i = 0; i <= chars.length - 10; i++) {
String str = s.substring(i, i+10);
if (set.contains(str)) {
resultSet.add(str);
} else {
set.add(str);
}
}
return new ArrayList<>(resultSet);
}
}
结果:
- 执行了17 ms,击败64%的用户
示例二:
class Solution {
static Map<Character, Integer> map = null;
static {
map = new HashMap<Character, Integer>() {{
put('A', 0);
put('C', 1);
put('G', 2);
put('T', 3);
}};
}
public List<String> findRepeatedDnaSequences(String s) {
int l = 10;
int strLen = s.length();
if (strLen <= l) {
return Collections.emptyList();
}
// 统计每个字符串出现的次数
Map<Integer, Integer> countMap = new HashMap<>();
List<String> result = new ArrayList<>();
int b = 0;
// 将前十个字符转为字节,每个字符占两个字节
for (int i = 0; i < l; i++) {
b = (b << 2) | map.get(s.charAt(i));
}
countMap.put(b, 1);
int a = ((1 << (l * 2)) - 1);
for (int i = 1; i <= strLen - l; i++) {
// 在后面追加一个字符
b = (b << 2) | map.get(s.charAt(i + l - 1));
// 去掉第一个字符
b = b & a;
int c = countMap.getOrDefault(b, 0) + 1;
countMap.put(b, c);
if (c == 2) {
result.add(s.substring(i, i + l));
}
}
return result;
}
}
结果:
怎么就更慢了呢,我不李姐,求大佬指教