
P5.2 GenomicRangeQuery
Find the minimal nucleotide from a range of sequence DNA.
-
P5.2 查询基因序列
在基因序列中寻找对应的最小的核苷酸
DNA序列可以表示为一个由字母A、C、G和T组成的字符串,四个字母分别对应于序列中不同类型的核苷酸。每个核苷酸都对应一个影响因子,它是一个整数,其中 A、C、G和T型核苷酸对应的影响因子分别为1、2、3和4。对于给定的DNA序列的特定部分,计算所含核苷酸对应的最小的影响因子是什么?
DNA序列以非空字符串形式给出,S=S[0]S[1]…S[N-1]由N个字符组成。有M次查询,用非空数组P和Q表示,每个数组由M个整数组成。第K次查询(0≤K<M),就是 要找出P[K]和Q[K]位置(含)之间的DNA序列中所含核苷酸对应的最小影响因子。
例如,考虑字符串S=“CAGCCTA”和数组P、Q,其中:
P[0]=2,P[1]=5,P[2]=0;Q[0]=4,Q[1]=5,Q[2]=6
3次查询的结果:
- K=0:也就是位置P[0]=2和Q[0]=4之间的部分DNA(GCC),其中含有核苷酸G和C(两个),其影响因素分别为3和2,因此最小的影响因子就是2;
- K=1:位置5和5之间的部分含有一个单核苷酸T,其影响因子是4,所以答案是4;
- K=2:位置0和6之间的部分(整个字符串)包含所有核苷酸,因此最小的影响因子就是核苷酸A对应的1。
编写函数:
def solution(S, P, Q)
给定一个由N个字符组成的非空字符串S和两个由M个整数组成的非空数组P和Q,返回一个由M个整数组成的数组,数组中的元素代表每次查询的结果。
例如,针对上面的例子,函数应返回值[2,4,1]。
假定:
- N是区间[1,100000]内的整数;
- M是范围[1,50000]内的整数;
- 数组P,Q的每个元素都是范围[0,n−1]内的整数;
- P[K]≤Q[K],其中0≤K<M;
- 字符串S仅由大写英文字母A、C、G、T组成。
- 解题思路
数组P和Q肯定是要遍历的,当P[K]和Q[K]差别很大时,在用遍历的方法取得最小值,时间复杂度就会不满足条件,因此需要优化获得最小值的方法。可以用空间来换取时间。针对4个核苷酸,每个核苷酸都计算下一个出现该核苷酸的索引(如果本身就是的话,则索引为当下索引)序列S_ss。
例如假设S=“AGG CTG GAAT”,则有,其中inf表示之后就没有出现过该核苷酸,表示无穷大的数
- S_ss_A=[0, 7, 7, 7, 7, 7, 7, 7, 8, inf]
- S_ss_G=[1, 1, 2, 5, 5, 5, 6, inf, inf, inf]
- S_ss_C=[3, 3, 3, 3, inf, inf, inf, inf, inf, inf]
- S_ss_T=[4, 4, 4, 4, 4, 9, 9, 9, 9, 9]
对于任何的S_ss而言,只要S_ss_X[P(K)]不大于Q(K),则说明X肯定在S[P(K):Q(K)+1]这一部分中。考虑到inf不利于编程,因此可以把inf换成-1,再多加一个判断即可。
- Python3代码
# -*- coding:utf-8 -*-
# &Author AnFany
# Lesson 5:Prefix Sums
# P 5.2 GenomicRangeQuery
def solution_direct(S, P, Q):
"""
按照数组给定的范围,返回字符串S在这个范围内对应的最小的数, 时间复杂度O(N * M)
:param S: 代表基因序列的字符串
:param P: 表示范围的数组
:param Q: 表示范围的数组
:return: 每一次查询的结果组成的列表
"""
impact_factor = {'A': 1, 'C': 2, 'G': 3, 'T': 4}
result = []
for i, j in zip(P, Q):
result.append(impact_factor[min(list(S[i: j+1]))])
return result
def next_occur(S, X):
"""
计算字符串S中,对于核苷酸X,下一个出现该核苷酸的索引,如果当前是X,则索引为当前的索引
:param S: DNA字符串
:param X: 核苷酸
:return: 所以序列
"""
index_list =[-1] * len(S)
for index, value in enumerate(S[::-1]): # 注意字符串反转
if value == X:
index_list[index] = len(S) - index - 1
else:
index_list[index] = index_list[index-1]
return index_list[::-1]
def solution(S, P, Q):
"""
按照数组给定的范围,返回字符串S在这个范围内对应的最小的数,时间复杂度O(N + M)
:param S: 代表基因序列的字符串
:param P: 表示起始位置的数组
:param Q: 表示结束位置的数组
:return: 每一次查询的结果组成的列表
"""
result = []
factor_list = ['A', 'C', 'G', 'T']
all_index_list = [next_occur(S, j) for j in factor_list]
for i in range(len(P)):
for j in range(len(factor_list)):
if all_index_list[j][P[i]] <= Q[i] and all_index_list[j][P[i]] != -1:
result.append(j + 1)
break
return result
- 结果
点击获得更多编程练习题。欢迎Follow,感谢Star!!! 扫描关注微信公众号pythonfan,获取更多。
网友评论