不断的遍历,如果 temp == template 并且 template 不在 res 当中,那么添加到 res 里去
classSolution{publicList<String>findRepeatedDnaSequences(String s){int len =10;int left =0;int start;int end;List<String> res =newArrayList<>();String template ="";String temp ="";while(left + len <= s.length()){
start = left +1;
end = start + len;
template = s.substring(left, left + len);while(end <= s.length()){
temp = s.substring(start, end);if(temp.equals(template)&&!res.contains(template))
res.add(temp);
start++;
end = start + len;}
left++;}return res;}}
II. 东哥的做法
法一:hash 暴力法
遍历所有含有 10 个元素的字符串,如果,有重复的,加入 res 里面
classSolution{publicList<String>findRepeatedDnaSequences(String s){Set<String> needs =newHashSet<>();Set<String> res =newHashSet<>();int len =10;String temp ="";for(int i =0; i + len <= s.length(); i++){
temp = s.substring(i, i + len);if(needs.contains(temp))
res.add(temp);else
needs.add(temp);}returnnewLinkedList<>(res);}}
假设s的长度为 N,目标子串的长度为 L(本题 L = 10),for 循环遍历 s 的O(N)个字符,对每个字符都要截取长度为 L 的子字符串,所以这个算法的时间复杂是O(NL)。
我们再想如果用传统的10进制来算,因为字符串固定 10 位,那么我们数字也要 10 位,而10 * 10 > 2147483647 已经超过了 int 的表示范围。我们其实只用了 4 个字母,那么其他的位数就浪费了,我们最终搞一个 4 进制就 ok 了
看下面一个小例子:
给你输入一个字符串形式的正整数,如何把它转化成数字的形式?
string s ="8264";int number =0;for(int i =0; i < s.size(); i++){// 将字符转化成数字
number =10* number +(s[i]-'0');print(number);}// 打印输出:// 8// 82// 826// 8264
因为我们默认的是 10 进制,接下来我们抽象一下:
/* 在最低位添加一个数字 */int number =8264;// number 的进制intR=10;// 想在 number 的最低位添加的数字int appendVal =3;// 运算,在最低位添加一位
number =R* number + appendVal;// 此时 number = 82643/* 在最高位删除一个数字 */int number =8264;// number 的进制intR=10;// number 最高位的数字int removeVal =8;// 此时 number 的位数intL=4;// 运算,删除最高位数字
number = number - removeVal *R^(L-1);// 此时 number = 264
四进制理解不了就用十进制理解,完了,一替换就完事了
理解了上面的代码,就可以看本题的代码了:
classSolution{publicList<String>findRepeatedDnaSequences(String s){int[] nums =newint[s.length()];//将字符串转换成数字数组for(int i =0; i < s.length(); i++){switch(s.charAt(i)){case'A':
nums[i]=0;break;case'C':
nums[i]=1;break;case'G':
nums[i]=2;break;case'T':
nums[i]=3;break;}}//存放字符对应的数字(哈希)Set<Integer> seen =newHashSet<>();//存放返回结果Set<String> res =newHashSet<>();//数字的位数int len =10;//进制intR=4;//用于减法的参数,类比十进制:564 = 8564 - 8 * (10^3)intRL=(int)Math.pow(R, len -1);int windowHash =0;int left =0, right =0;while(right < s.length()){//向右扩展窗口,增加位数
windowHash = windowHash *R+ nums[right];
right++;//当长度为 10 再进行操作if(right - left == len){if(seen.contains(windowHash))
res.add(s.substring(left, right));else
seen.add(windowHash);//窗口收缩,左边缘右移
windowHash = windowHash - nums[left]*RL;
left++;}}returnnewLinkedList<>(res);}}