重复的DNA序列[hash判定重复+滑动窗口+二进制编码之位运算]

前言

判定数组中重复的数字时,可用hash记录;把数组变成字符串,判定字串是否重复时,可hash记录滑动窗口中的字串;但是字符串的hashcode获取可是要扫描字符串,而Character/Integer是直接获取原值作为hashcode(hashcode需要干扰之后作为hash值。),所以当字串字符进行二进制编码,让字符串映射到数值,快速获取hashcode.

一、“重复” 的DNA序列

二、hash配重复 + 二进制编码

在这里插入图片描述

1、hash寻找重复

public List<String> findRepeatedDnaSequences(String s) {
        int n = s.length();

        Set<String> pool = new HashSet<>();
        Set<String> ans = new HashSet<>();

        for(int i = 0;i < n - 9;i++){
            String str = s.substring(i,i + 10);
            if(pool.contains(str) && !ans.contains(str)) ans.add(str);

            pool.add(str);
        }
        return new ArrayList<>(ans);
    }

2、二进制编码之位运算练习

package everyday.bitManipulation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// 重复的DNA序列。
public class FindRepeatedDnaSequences {
    /*
    由于获取字符串的hashcode需要扫描整个字符串,所以可将少量字符串编码,即为了10子串的编码。
     */
    public List<String> findRepeatedDnaSequences(String s) {
        int n = s.length();
        List<String> ans = new ArrayList<>();

        if (n <= L) return ans;
        // 初始化前9个数。
        int x = 0, i = 0;
        while (i < L - 1) x = x << 2 | fx.get(s.charAt(i++));
        // 开始用滑动窗口拿子串的integer编码作为hash的key
        Map<Integer, Integer> cnt = new HashMap<>();
        while (i < n) {
            x = (x << 2 | fx.get(s.charAt(i))) & (1 << L * 2) - 1;

            cnt.put(x, cnt.getOrDefault(x, 0) + 1);

            if (cnt.get(x) == 2) ans.add(s.substring(i - L + 1, i + 1));

            ++i;
        }
        return ans;
    }

    final static int L = 10;
    static Map<Character, Integer> fx = new HashMap<>();

    static {
        fx.put('A', 0);
        fx.put('C', 1);
        fx.put('G', 2);
        fx.put('T', 3);
    }
}

总结

1)二进制编码不仅可为字符串编码,常见的还有子集场景中,二进制映射到子集;二进制还可以将0/1 hash降维,比如一个值可以代替31位0-1hash,对付26个字母等绰绰有余。
2)二进制/位运算很重要,多练习,对很多问题优化有帮助。
3)字符串的hashcode获取不是O(1),而是O(n),字符/整数是O(1).

参考文献

[1] LeetCode 187.重复的DNA序列

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值