HashSet优化小窍门

2016-08-03  本文已影响178人  Isabella10

hashSet是很好用的,但是,如果key太长了,怎么优化呢?


187. Repeated DNA Sequences

题目

给出一个DNA字符串,里面仅包含字符'A','C',G','T'
要求超出 长度为10的,而且重复出现的子串

思考

每个大于10的子串都是一个HashSet Object?
滑动窗(窗长为10)的形式,从左滑到右
如果在HashSet里面没有出现过,put 进去
如果出现过,add 到 answer里面
如果出现两次以上,不就重复添加了吗?

思路

** 2 HashSet + sliding window **


优化 HashSet

那么,题目给出'A','C','G','T'有什么意义呢?
10个字符串作为一个HashSet Object, 超时!
怎么才能更快、而且用更少的空间去记录这10个字符串呢?

解决方法 : 编码

A : 0 (00)
C : 1 (01)
G : 2 (10)
T : 3 (11)
这样,10个长度的字符串就是一个 20位的二进制编码
我们可以使用
int hash_num = 0;
hash_num = (hash_num<<2) + ch.get('A')
的形式来构造20位的编码。
遍历的时候,先左移2位,或上新的字符,
因为这么操作,所以10个字符输入后,共22位,
我们只要处理一下,保留最低的20位作为hash_num即可。


具体代码:

    public List<String> findRepeatedDnaSequences(String s) {
        
        List<String> ans = new ArrayList<String>();
        if(s == null || s.length()<=10)
            return ans;
        
        HashMap<Character, Integer> ch = new HashMap<Character, Integer>();
        ch.put('A', 0);
        ch.put('C', 1);
        ch.put('G', 2);
        ch.put('T', 3);
        
        HashSet<Integer> set = new HashSet<Integer>();
        HashSet<Integer> set2 = new HashSet<Integer>();  // 防止符合条件的字串重复添加到ans里面
        
        int hash_num = 0;
        for(int i=0; i<s.length(); i++)
        {
            if(i<9)
            {
                hash_num <<= 2;
                hash_num |= ch.get(s.charAt(i));
            }
            else
            {
                hash_num <<= 2;
                hash_num |= ch.get(s.charAt(i));
                int mask = (1<<20)-1; // 10000...00(21bits) --> 0111..111(20bits of 1)
                hash_num &= mask;
                if(set.contains(hash_num) && !set2.contains(hash_num))
                {
                    ans.add(s.substring(i-9, i+1));
                    set2.add(hash_num);
                }
                else
                    set.add(hash_num);
            }
        }
        return ans;
    }

小收获

  1. 不管是HashSet 还是 HastMap, 如果能够发现输入的规律,适当进行编码,可以压缩空间,而且用Integer替换String可以提高速度。

上一篇下一篇

猜你喜欢

热点阅读