【每日一题】重复的DNA序列

Tag

【哈希表】【位运算+滑动窗口+哈希表】【字符串】【2023-11-05】


题目来源

187. 重复的DNA序列


题目解读

找出字符串中重复出现的字符串。


解题思路

方法一:哈希表

一种朴素的方法是枚举所有长度为 10 的子字符串,并用哈希表计数,如果该子字符串的出现的次数超过一次,那么该子字符串就是答案要求的重复的 DNA 序列。

实现代码

class Solution {
public:
    vector<string> findRepeatedDnaSequences(string s) {
        unordered_map<string, int> cnts;
        int n = s.size();
        vector<string> res;
        for (int i = 0; i <= n - 10; ++i) {
            string sub = s.substr(i, 10);
            if (++cnts[sub] == 2) {
                res.push_back(sub);
            }
        }
        return res;
    }
};

复杂度分析

时间复杂度: O ( N ⋅ L ) O(N \cdot L) O(NL) N N N 为字符串的 s 的长度, L L L 为固定的字符串的大小。

空间复杂度: O ( N ) O(N) O(N)

方法二:哈希表+滑动窗口+位运算

实际上我们可以使用一个固定大小的滑窗来记录长度为 10 的字符串。题目中已告知我们字符串中的字符种类只有四种,因此可以使用 2 个比特来表示每个字符,于是可以有:

  • A 表示为二进制为 00
  • C 表示为二进制为 01
  • G 表示为二进制为 10
  • T 表示为二进制为 11

这样的话长度为 10 的字符串就可以使用 20 为比特来表示即一个 int 型整数,也就是说滑窗内的字符串可以使用一个 int 型整数表示,这样就降低了时间复杂度。具体地:

  • 先向滑窗中塞进去 9 个字符;
  • 滑窗每向右移动一位,滑窗内就会增加一个字符,滑窗最左侧的字符离开窗口:
    • 滑窗每向右移动一位,滑窗内就会增加一个字符,表示滑窗内字符串的二进制整数值 x = x << 2x = x | bin[ch]bin[ch] 表示字符 ch 对应的二进制;
    • 滑窗左侧的字符离开窗口,x = x & ((1 << 20) - 1),因此时 x22 位比特,我们只需要低 20 位,所以与上 (1 << 20) - 1
  • 剩下就是更新哈希表,一旦有第二次出现的 x,则表示的字符串就是重复的 DNA 序列。

实现代码

class Solution {
public:
    unordered_map<char, int> bin = {{'A', 0}, {'C', 1}, {'G', 2}, {'T', 3}};
    vector<string> findRepeatedDnaSequences(string s) {
        vector<string> res;
        int n = s.size();
        if (n <= 10) {
            return res;
        }

        int x = 0;
        for (int i = 0; i < 9; ++i) {
            x = (x << 2) | bin[s[i]];
        }
        unordered_map<int, int> cnts;
        for (int i =0; i <= n - 10; ++i) {
            x = ((x << 2) | bin[s[i + 10 - 1]]) & ((1 << 20) - 1);
            if (++cnts[x] == 2) {
                res.push_back(s.substr(i, 10));
            }
        }
        return res;
    }
};

复杂度分析

时间复杂度: O ( N ) O(N) O(N) N N N 为字符串的 s 的长度, L L L 为固定的字符串的大小。

空间复杂度: O ( N ) O(N) O(N)


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_nn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值