思路:滑动窗口 + 位运算
- 滑动窗口的关键在于,利用旧序列和新序列的相似性降低运算的复杂度
- 此题中只有4个字母,那么可以使用2位
bit来记录每一个字母 - 滑动窗口一入一出,更新记录当前的10个字母的整数
res_bit - 如何把右边的读进来?1.左移两位
res_bit <<= 2 2.把右边的读进来 res_bit |= to_bin[ch] - 如何把左边的弹出去?希望最左边的两位(左数第21 22两位)变成0,也就是希望 & 0111111… 其中,0处在第20位上,
x & ((1 << 20) - 1) - 哈希表里面的key就是位运算的结果x, value就是出现的次数
- 如何返回需要的字符串呢?需要边读边更新哈希表,如果出现的次数 >= 2,说明应该返回此时的位置了
代码:
class Solution: def __init__(self): self.L = 10 self.to_bin = {'A': 0, 'C': 1, 'G': 2, 'T': 3} def findRepeatedDnaSequences(self, s: str) -> List[str]: ''' 位运算: * 每个数字用两位的二进制字符来表示 * 如何把右边的读进来?1.左移两位 x <<= 2 2.把右边的读进来 x |= to_bin[ch] * 如何把左边的弹出去?希望最左边的两位(左数第21 22两位)变成0,也就是希望 & 0111111... 其中,0处在第20位上 即 x & ((1 << 20) - 1) 滑动窗口 + 哈希表: * 哈希表里面的key就是位运算的结果x, value就是出现的次数 * 如何返回需要的字符串呢?需要边读边更新哈希表,如果出现的次数 >= 2,说明应该返回此时的位置了 ''' len_s = len(s) # 读掉边缘情况 if len_s <= 10: return [] cnt_str = collections.defaultdict(int) list_str = list() # 创建第一个滑动窗口 bit_res = 0 for i in range(self.L): bit_res = (bit_res << 2) | self.to_bin[s[i]] cnt_str[bit_res] += 1 # 滚动更新哈希表和滑动窗口 for i in range(self.L, len_s): # 右边的移动进来 bit_res = ((bit_res << 2) | self.to_bin[s[i]]) # 左边的移动出去 bit_res = (bit_res & ((1 << (2 * self.L)) - 1)) # 更新哈希表 cnt_str[bit_res] += 1 # 如果次数 >= 2 if cnt_str[bit_res] == 2: list_str.append(s[i - self.L + 1: i + 1]) return list_str