Repeated DNA Sequences

Repeated DNA Sequences_第1张图片

1. 解析

题目大意,找出至少出现两次的10个字母子序列,整体上不是很难,只需借助hashtable进行查找即可.

2. 分析

每次取10个字符,如题目中所给的示例,"AAAAACCCCC",然后将其放进hashtable当中进行存储,记录其出现的次数,然后移动到下一个位置,接着取"AAAACCCCCC",在hashtable中查找其出现的次数,若当前没有出现过,则将其放进hashtable当中,并记录它出现的次数为1;当且仅当之前出现过的次数为1,意味着出现至少2次,将其放进结果集中,以后再次出现就无需添加在结果集当中,一直往下搜索即可.

注意:出现两次以上的子串只需保存一次就行,故我们采用hashtable的value值保存其出现的次数

class Solution {
public:
    vector findRepeatedDnaSequences(string s) {
        vector res;
        if (s.length() <= 10) return res;
        map allString;
        for (int pos = 0; pos < s.length() - 9; ++pos){
            string substr = s.substr(pos, 10);
            if (allString[substr] == 1){ //第二次出现
                res.push_back(substr);
            }
            allString[substr]++; //为了重复添加,增加计数的标识
        }
        return res;
    }
};

 3. 位操作解法

上述的解法存在一个问题就是,采用hashtable存储的key是字符串的形式,每次要开辟10个字节空间,为了减少开辟存储key值的空间,我们也可以采用位操作,从而用整形替代字符串作为key,观察发现,DNA序列,实则就是由A、C、G、T这四种字母组成,采用ASCII二进制编码分别为A(65)、C(67)、G(71)、T(84) 

A------01000001        C------01000011        G------01000111          T------01010010

后三位编码是不一样的,这也是设计这道题的核心所在,不过还是比较难想的,我不是很清楚别的博主是怎么get到这个点的,所以我们可以将后三位编码作为区别这四个字母的标识,先获取前9个字符的二进制编码,例如题目中的例子,"AAAAACCCC"-----001 001 001 001 001 011 011 011 011,然后从第10个字符开始,每次往左移动3位,为了及时记录当前的9个字符的二进制编码,我们需要一个27位全为1的掩码0x7FFFFFF,这样就可以将string类型的key转换成了int数据类型,大大减少了比较的时间和空间

class Solution {
public:
    vector findRepeatedDnaSequences(string s) {
        vector res;
        int mask = 0x7ffffff, cur = 0;
        map allString;
        
        for (int i = 0; i < 9; ++i) cur = (cur << 3) | (s[i] & 7);
        for (int i = 9; i < s.length(); ++i){
            cur = ((cur & mask) << 3) | (s[i] & 7);
            if (allString[cur] == 1) res.push_back(s.substr(i-9, 10));
            allString[cur]++;
        }
        return res;
    }
};

 

你可能感兴趣的:(#,位运算)