LeetCode-187. 重复的DNA序列-Java-medium

题目链接

法一(哈希)
    /**
     * 法一(哈希)
     *
     * @param s
     * @return
     */
    public List<String> findRepeatedDnaSequences(String s) {
        List<String> ans = new LinkedList<>();
        Set<String> set = new HashSet<>();
        for (int i = 0; i <= s.length() - 10; i++) {
            String sub = s.substring(i, i + 10);
            if (set.contains(sub) && !ans.contains(sub)) { // 遇到过sub并且它还未加入到ans
                ans.add(sub);
            } else {
                set.add(sub);
            }
        }
        return ans;
    }
法二(哈希 + 滑动窗口 + 位运算)
    /**
     * 静态变量
     */
    final static int L = 10; // 滑动窗口长度
    static Map<Character, Integer> fx = new HashMap<>(); // 字母与对应二进制的映射

    /**
     * 静态代码块
     */
    static {
        fx.put('A', 0); // A对应二进制00
        fx.put('C', 1); // C对应二进制01
        fx.put('G', 2); // G对应二进制10
        fx.put('T', 3); // T对应二进制11
    }

    /**
     * 法二(哈希 + 滑动窗口 + 位运算)
     * 1. 改进
     *    字符串进行哈希查找的时间复杂度是O(n),而字符/整数是O(1),故考虑将字符串转化为整数
     * 2. 思路
     *   (1)字符A、C、G、T分别用数字1、2、3、4表示,对应的二进制分别为00、01、10、11
     *   (2)这样字符串ACGT就可以表示为00011011,对应的数字是27
     *   (3)由于滑动窗口长度为10,故可以将滑动窗口范围内的字符串表示为整型数字(整型数字有32位)
     * 3. 细节
     *   (1)字符串新增一个字符
     *        x = x << 2 | fx.get(s.charAt(i));
     *   (2)二进制数保留20位
     *       x = x & (( 1 << 20 ) - 1);
     *
     * @param s
     * @return
     */
    public List<String> findRepeatedDnaSequences_2(String s) {
        int n = s.length(), x = 0;
        List<String> ans = new LinkedList<>();
        Map<Integer, Integer> cnt = new HashMap<>();
        if (n <= L) { // s的长度小于滑动窗口长度
            return ans;
        }
        for (int i = 0; i < L - 1; i++) {  // 求解初始时滑动窗口范围内字母组成的数字x
            x = x << 2 | fx.get(s.charAt(i));
        }
        for (int i = 0; i <= n - L; i++) { // 窗口每次向右滑动一个单位,总共滑动 n - L + 1 次
            x = (x << 2 | fx.get(s.charAt(i + L - 1))) & (1 << L * 2) - 1; // 计算当前位置滑动窗口范围内字母组成的数字x
            cnt.put(x, cnt.getOrDefault(x, 0) + 1); // 统计x出现的次数
            if (cnt.get(x) == 2) { // 如果x出现2次,则将x对应的字符串加入ans
                ans.add(s.substring(i, i + L));
            }
        }
        return ans;
    }
本地测试
        /**
         * 187. 重复的DNA序列
         */
        lay.showTitle(187);
        Solution187 sol187 = new Solution187();
        String s187 = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT";
        System.out.println(s187);
        List<String> ans187_1 = sol187.findRepeatedDnaSequences(s187);
        System.out.println(ans187_1.toString());
        List<String> ans187_2 = sol187.findRepeatedDnaSequences_2(s187);
        System.out.println(ans187_2.toString());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值