【187中等】重复的DNA序列

【187中等】重复的DNA序列(2021.10.8)

1. 问题描述

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

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

示例1:

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

示例2:

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

提示:

  • 0 <= s.length <= 105
  • s[i]'A''C''G''T'
2. 思路
  1. 要注意边界条件(字符串长度不满10)

    遍历原来字符串中长度为10的字串,使用map来存储字符串出现的次数,滑动窗口

    最后返回出现次数超过1的字串

  2. 编码,位运算,很巧妙,值得学习,

3. 代码
class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        int n = s.size();
        if(n < 10) {
            return {};
        }
        map<string, int> map;
        vector<string> result;
        string temp = "";
        for(int i = 0; i < n - 9; i++) {
            temp = s.substr(i, 10);
            map[temp]++;
        }
        for(auto iter = map.begin(); iter != map.end(); iter++) {
           if(iter -> second > 1) {
               result.push_back(iter -> first);
           }
        }
        return result;
    }
};

思路一致,写法有优化:

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        vector<string> ans;
        unordered_map<string, int> count;
        for (int i = 0; i <= int(s.size()) - 10; i++) {
            string str = s.substr(i, 10);
            count[str]++;
        }
        for (auto &it : count) {
            if (it.second >= 2)
                ans.push_back(it.first);
        }
        return ans;
    }
};
作者:bianchengxiong
链接:https://leetcode-cn.com/problems/repeated-dna-sequences/solution/acmjin-pai-ti-jie-you-xiao-dai-ma-10xing-b2gu/

采用位运算

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        //对应二进制00, 01, 10, 11.那么10个组合只要20位就够了。
        unordered_map<char, int> m{{'A', 0}, {'C', 1}, {'G', 2}, {'T', 3}};
        vector<string> res;
        bitset<1 << 20> s1, s2; //那么所有组合的值将在0到(1 << 20 - 1)之间
        int val = 0, mask = (1 << 20) - 1; //mask等于二进制的20个1
        //类似与滑动窗口先把前10个字母组合
        for (int i = 0; i < 10; ++i) val = (val << 2) | m[s[i]];
        s1.set(val); //置位
        for (int i = 10; i < s.size(); ++i) {
            val = ((val << 2) & mask) | m[s[i]]; //去掉左移的一个字符再加上一个新字符
            if (s2.test(val)) continue; //出现过两次跳过
            if (s1.test(val)) {
                res.push_back(s.substr(i - 9, 10));
                s2.set(val);
            }
            else s1.set(val);
        }
        return res;
    }
};

c++ bitset用法

4. 复杂度

时间复杂度: O(n),n表示字符串的长度

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值