187. 重复的DNA序列

417 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

187. 重复的DNA序列

所有 DNA 都由一系列缩写为 'A','C','G' 和 'T' 的核苷酸组成,例如:"ACGAATTCCG"。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。

编写一个函数来找出所有目标子串,目标子串的长度为 10,且在 DNA 字符串 s 中出现次数超过一次。

  • 示例 1:

输入:s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" 输出:["AAAAACCCCC","CCCCCAAAAA"]

  • 示例 2:

输入:s = "AAAAAAAAAAAAA" 输出:["AAAAAAAAAA"]

解题思路

使用滑动窗口+位运算

  1. 使用Map可以在O(1)的时间复杂度内获得目标子串出现的次数
  2. 但是因为0 <= s.length <= 100000,因此如果使用map统计长度为 10的目标子串,空间复杂度非常高。但是因为所有 DNA 都由一系列缩写为 'A','C','G' 和 'T' 的核苷酸组成,所以我们可以使用2位二进制表示一个字符,那么长度为10的目标子串也就只需要一个32位的整型来表示
  3. 朴素的解法中,需要枚举所有长度为10的目标子串,时间复杂度为o(10*s.length),我们可以使用滑动窗口,维护窗口内的字符串组成,时间复杂度为o(s.length)

代码

class Solution {
    public  String decode(int tar) {
        StringBuilder sb = new StringBuilder();
        for (int i=0;i<10;i++)
        {
            int cur=tar&3;
            if (cur==0)
                sb.append('A');
            else if(cur==1)
                sb.append('C');
            else if(cur==2)
                sb.append('G');
            else sb.append('T');
            tar>>=2;
        }
        return sb.reverse().toString();
    }
    public  int count(char c) {

        if (c=='A')
            return 0;
        else if(c=='C')
            return 1;
        else if(c=='G')
            return 2;
        else return 3;
    }
    public  List<String> findRepeatedDnaSequences(String s) {
        ArrayList<String> strings = new ArrayList<>();
        Map<Integer,Integer> map=new HashMap<>();
        int cur=0,l=0,r=0,n=s.length(),mask=(1<<20)-1;
        while (r<n)
        {
          if (r-l>=10)
          {
              map.put(cur,map.getOrDefault(cur,0)+1);
              cur-=(count(s.charAt(l++))<<18);

          }
          cur<<=2;
          cur+=count(s.charAt(r++));
        }
        map.put(cur,map.getOrDefault(cur,0)+1);
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue()>1)
                strings.add(decode(entry.getKey()));
        }
        return strings;
    }
}