原文地址:http://www.cnblogs.com/grandyang/p/4284205.html
All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.
Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.
For example,
Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT", Return: ["AAAAACCCCC", "CCCCCAAAAA"].
看到这道题想到这应该属于CS的一个重要分支生物信息Bioinformatics研究的内容,研究DNA序列特征的重要意义自然不用多说,但是对于我们广大码农来说,还是专注于算法吧,此题还是用位操作Bit Operation来求解,计算机由于其二进制存储的特点可以很巧妙的解决一些问题,像之前的Single Number 单独的数字和Single Number II 单独的数字之二都是很巧妙利用位操作来求解。此题由于构成输入字符串的字符只有四种,分别是A, C, G, T,下面我们来看下它们的ASCII码用二进制来表示:
A: 0100 0001 C: 0100 0011 G: 0100 0111 T: 0101 0100
由于我们的目的是利用位来区分字符,当然是越少位越好,通过观察发现,每个字符的后三位都不相同,故而我们可以用末尾三位来区分这四个字符。而题目要求是10个字符长度的串,每个字符用三位来区分,10个字符需要30位,在32位机上也OK。为了提取出后30位,我们还需要用个mask,取值为0x7ffffff,用此mask可取出后27位,再向左平移三位即可。算法的思想是,当取出第十个字符时,将其存在哈希表里,和该字符串出现频率映射,之后每向左移三位替换一个字符,查找新字符串在哈希表里出现次数,如果之前刚好出现过一次,则将当前字符串存入返回值的数组并将其出现次数加一,如果从未出现过,则将其映射到1. 代码如下:
之后在网上看到一个丧心病狂般简洁的版本,但是愚以为代码当然以简洁为美,但是过分力求简洁而疯狂压缩代码使其某一行看上去异常复杂也是不太可取的,这里贴上此版本,基本思路还是相同的。
vector<string> findRepeatedDnaSequences(string s) { unordered_map<int, int> m; vector<string> r; int t = 0, i = 0, ss = s.size(); while (i < ss) if (m[t = (t << 3 | s[i++] & 7) & 0x3FFFFFFF]++ == 1) r.push_back(s.substr(i - 10, 10)); return r; }