[leetcode] 187.Repeated DNA Sequences

来源:互联网 发布:最好的身份证网络投资 编辑:程序博客网 时间:2024/06/08 10:28

题目:
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”].
题意:
所有的DNA包含A,C,G,T四种核苷酸。给定一个DNA的字符串,查找是否有长度为10的,重复出现的子串。
比如 “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”中,”AAAAACCCCC”, “CCCCCAAAAA”都出现了两次。
思路:
对于这道题最原始的思路就是从前往后扫描一遍判断每个长度为10的字符串是否在hash表中已经存在了,如果存在了说明是有重复的,如果是第二次加入hash表(hash表需要记录已经扫描到了这个字符串多少次)则将这个字符串加入到结果中。如果没有在hash表中出现的话,那么将该字符串加入到hash表中。
得到一般的思路后就是来优化该现有的思路。对于字符串,C++是一个类,因此不单单是需要记录该字符串中存放的字符数据,还要存放一些额外的信息,比如用来记录是否能够修改该字符串的计数信息(具体细节请阅读STL相关知识中的内容)。也就说如果使用字符串作为hash的键,那么需要耗费的空间会过大。所以我们需要将键值需要的空间减少。考虑到一个字符对应的空间是8个bit位,但是现在我们只需要4个字母,所以2个bit位就可以用来区分这四个字符了。比如用”00”代表A,”01”代表C,”10”代表G,“11”代表T。那么对于一个10位长的字符串,我们使用10*2=20个bit位就可以记录,一个int是32个bit位,所以用一个int值就能代表10个字符的字符串,作为键值。
再考虑一共有多少种不同的键值,10个字符的位置,每个位置都可能出现这4个字符,所以一共有4^10种可能,即1024*1024种可能。因此我们可以通过使用一个1024*1024的数组作为hash表的方法来加快查找速度。另外我们需要记录每个子字符串出现的次数,当第二次出现时我们才将该字符串加入到我们最终的结果中。所以需要记录次数,这里我使用一个char来记录次数,当次数是0时,代表之前还没加入过这个子字符串,那么令次数=1,如果次数=1,那么说明之前出现过了一次,那么将这个子字符串加入到结果中,并将次数设置为2,其余情况就是已经出现大于等于2次,无需处理了。
优化的技术已经阐述,接下来就是具体做法,用int index记录了子字符串对应的在数组中的位置,我们顺序从左往右扫描字符串。比如第一次需要记录前十个字符对应的下标index。那么接下来让i从第11个位置开始往后扫描,i的意思就是子字符串结束的位置,那么只需要让index右移两位,并且清空前面12位的内容,也就是说原来的二十位bit右移两位后,原来的最高两个位置到达了第21,22的位置,最低的两个位置变到了第3,4位,所以此刻第1,2两个bit位上是空的(即0)。那么此刻我们置零第21,22bit位,相当于移除了之前子字符串的最高位,并且在最右边加上此刻i出字符对应的两个bit位的值。
以上。
代码如下:

class Solution {public:    vector<string> findRepeatedDnaSequences(string s) {        vector<string>result;        if (s.size() <= 10)return result;        vector<char> hash(1024 * 1024, 0);        int index = 0;        for (auto j = 0; j < 10; j++) {            index <<= 2;            switch (s[j]) {                case 'A':  break;                case 'C': {                              index |= 0x01;                              break;                }                case 'G': {                              index |= 0x02;                              break;                }                case 'T': {                              index |= 0x03;                              break;                }            }        }        hash[index] = 1;        for (auto i = 10; i < s.length(); i++) {            index <<= 2;            index &= 0x000fffff;            switch (s[i]) {            case 'A': break;            case 'C': {                          index |= 0x01;                          break;            }            case 'G': {                          index |= 0x02;                          break;            }            case 'T': {                          index |= 0x03;                          break;            }            }            if (hash[index] == 1) {                result.push_back(s.substr(i - 9, 10));                hash[index]++;            }            else if (hash[index] == 0)hash[index] = 1;        }        return result;    }};
0 0
原创粉丝点击