leetcode 187. Repeated DNA Sequences 編碼計數統計重複字串 + 移動視窗
阿新 • • 發佈:2019-01-01
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: “ACGAATTCCG”. When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.
Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.
For example,
Given s = “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”,
Return:
[“AAAAACCCCC”, “CCCCCAAAAA”].
這道題考察的就是重複出現的字串,這道題給我的啟發很強。
當然,最直接的方法就是暴力求解,但是這個會超時,其實也可以採用HashMap來做(這個方法也可以直接accept),我在網上看到了一個基於編碼的做法,這個做法很棒,直接看程式碼吧!
這道題十分需要注意的地方就是位運算的優先順序,注意所有的位運算以後都注意要新增括號,因為加法的優先順序高於位運算,所以不新增括號是錯誤的。
程式碼如下:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/*
* http://blog.csdn.net/xudli/article/details/43666725
*
* 因為只有4個字母,所以可以建立自己的hashkey, 每兩個BITS,
*
* 對應一個 incoming character. 超過20bit 即10個字元時, 只保留20bits.
*
* (hash<<2) + map.get(c) 符號優先順序, << 一定要括起來.
*
* */
public class Solution
{
/*
* 這個是網上編碼的做法,很不錯的想法,值得反思和學習
* 不過有點麻煩
* */
public List<String> findRepeatedDnaSequencesByCode(String s)
{
List<String> res=new ArrayList<>();
if(s==null || s.length()<=10)
return res;
Map<Character, Integer> map=new HashMap<Character, Integer>();
map.put('A', 0);
map.put('C', 1);
map.put('G', 2);
map.put('T', 3);
/*
* set儲存的是所有的可能的字串,
* uniqueSet儲存的的是判斷的重複出現的字串
* 使用uniqueSet是為了避免重複新增重複元素
* */
Set<Integer> set=new HashSet<>();
Set<Integer> uniqueSet=new HashSet<>();
int hash=0;
for(int i=0;i<s.length();i++)
{
Character one=s.charAt(i);
if(i<9)
hash = (hash<<2) + map.get(one);
else
{
hash = (hash<<2) + map.get(one);
hash &= (1<<20)-1;
if(set.contains(hash)==false)
set.add(hash);
else if(set.contains(hash) && !uniqueSet.contains(hash))
{
uniqueSet.add(hash);
res.add(s.substring(i-9,i+1));
}
}
}
return res;
}
/*
* 使用HashMap去做,這個也很不錯,可以直接accept
*
* */
public List<String> findRepeatedDnaSequences(String s)
{
List<String> res=new ArrayList<>();
if(s==null || s.length()<=10)
return res;
Map<String, Integer> map=new HashMap<>();
for(int i=10;i<=s.length();i++)
{
String key=s.substring(i-10, i);
map.put(key, map.getOrDefault(key, 0)+1);
}
Set<String> set=map.keySet();
for(String key : set)
{
if(map.get(key)>=2)
res.add(key);
}
return res;
}
/*
* 暴力去做,這個肯定超時
* */
public List<String> findRepeatedDnaSequencesByLoop(String s)
{
List<String> res=new ArrayList<>();
if(s==null || s.length()<=10)
return res;
for(int i=0;i<s.length();i++)
{
if(i+10<=s.length())
{
String one=s.substring(i,i+10);
for(int j=i+1;j<s.length();j++)
{
if(j+10<=s.length())
{
if(one.equals(s.substring(j, j+10)))
{
if(!res.contains(one))
res.add(one);
break;
}
}else
break;
}
}
else
break;
}
return res;
}
}
下面是C++的做法,這道題最直接的方法就是使用map來做查詢,但是可能超時,後來網上看到了一個使用編碼的做法,很棒的做法,值得學習
程式碼如下:
#include <iostream>
#include <algorithm>
#include <climits>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
using namespace std;
class Solution
{
public:
vector<string> findRepeatedDnaSequences(string s)
{
vector<string> res;
map<char, int> mmp;
mmp['A'] = 0;
mmp['C'] = 1;
mmp['G'] = 2;
mmp['T'] = 3;
set<int> st;
set<int> uniqueSt;
int hash = 0;
for (int i = 0; i < s.length(); i++)
{
if (i < 9)
hash = (hash << 2) + mmp[s[i]];
else
{
hash = (hash << 2) + mmp[s[i]];
hash = hash & ((1 << 20) - 1);
if (st.find(hash) == st.end())
st.insert(hash);
else if (uniqueSt.find(hash) == uniqueSt.end())
{
uniqueSt.insert(hash);
res.push_back(s.substr(i-9,10));
}
}
}
return res;
}
};