leetcode187. 重复的DNA序列

DNA序列 由一系列核苷酸组成,缩写为 ‘A’, ‘C’, ‘G’ 和 ‘T’.。

例如,“ACGAATTCCG” 是一个 DNA序列 。
在研究 DNA 时,识别 DNA 中的重复序列非常有用。

给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。

示例 1:

输入:s = “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”
输出:[“AAAAACCCCC”,“CCCCCAAAAA”]
示例 2:

输入:s = “AAAAAAAAAAAAA”
输出:[“AAAAAAAAAA”]

提示:

0 <= s.length <= 105
s[i]==‘A’、‘C’、‘G’ or ‘T’

解题思路:
hash+滑动窗口+二进制位运算

通过hash能够快速查找之前是否出现过,通过二进制运算可以将字符串转换成二进制整数,因为题目给的字符是四个那么就是可以用两位表示出字符 例如 A;00 C:01 G:10 T:11。窗口长度为10。

  1. 首先将第一个窗口计算出来,通过每次左移两位,并且 | 最新的值。将得到值写入hash中
  2. 窗口向右移动,左移加上新增的两位,并且通过&运算去掉头两位,具体的做法就是 (1 << 20) - 1 这样的到一个20位全是1的值,超过20位的部分都是0,&上刚刚的值就可以只保留后20位。
  3. 判断是否出现过,如果出现过填充字符串,注意 字符串的长度是10, 那么字符串的起点就是 end - 10 + 1,包括end本身。

代码如下:

class Solution {
public:
    int helper(char s) {
        if (s == 'A') return 0;
        else if (s == 'C') return 1;
        else if (s == 'G') return 2;
        else return 3;
    }
    int L = 10;//长度
    int Left = 2;//字符对应的二进制长度
    vector<string> findRepeatedDnaSequences(string s) {
        unordered_map<int,int>counts;
        vector<string>res;
        int end = 0, x = 0;
        if (s.size() < 10) return res;
        for (; end < 10; ++end) x = (x << Left) | helper(s[end]);
        counts[x] = 1;
        for (; end < s.size(); ++end) {
            x = ((x << Left) | helper(s[end])) & ((1 << (Left * L)) - 1);
            if (counts[x]++ == 1) {
                res.emplace_back(s.substr(end - L + 1, L));
            }
        }
        return res;
    }
};

你可能感兴趣的:(leetcode,leetcode)