Codility每周一课:L5 Prefix Sums(P5.2)

4734220-29a9fb858ca70604.png
0.png

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次查询的结果:

  1. K=0:也就是位置P[0]=2和Q[0]=4之间的部分DNA(GCC),其中含有核苷酸G和C(两个),其影响因素分别为3和2,因此最小的影响因子就是2;
  2. K=1:位置5和5之间的部分含有一个单核苷酸T,其影响因子是4,所以答案是4;
  3. K=2:位置0和6之间的部分(整个字符串)包含所有核苷酸,因此最小的影响因子就是核苷酸A对应的1。

编写函数:

def solution(S, P, Q)

给定一个由N个字符组成的非空字符串S和两个由M个整数组成的非空数组P和Q,返回一个由M个整数组成的数组,数组中的元素代表每次查询的结果。

例如,针对上面的例子,函数应返回值[2,4,1]。

假定:

  1. N是区间[1,100000]内的整数;
  2. M是范围[1,50000]内的整数;
  3. 数组P,Q的每个元素都是范围[0,n−1]内的整数;
  4. P[K]≤Q[K],其中0≤K<M;
  5. 字符串S仅由大写英文字母A、C、G、T组成。
  • 解题思路

数组P和Q肯定是要遍历的,当P[K]和Q[K]差别很大时,在用遍历的方法取得最小值,时间复杂度就会不满足条件,因此需要优化获得最小值的方法。可以用空间来换取时间。针对4个核苷酸,每个核苷酸都计算下一个出现该核苷酸的索引(如果本身就是的话,则索引为当下索引)序列S_ss。

例如假设S=“AGG CTG GAAT”,则有,其中inf表示之后就没有出现过该核苷酸,表示无穷大的数

扫描二维码关注公众号,回复: 5212123 查看本文章
  • 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
  • 结果
4734220-77eaf324b9c72b71
image

点击获得更多编程练习题。欢迎Follow,感谢Star!!! 扫描关注微信公众号pythonfan,获取更多。

4734220-3a38d3c2af6073bb
image
4734220-28f0bd9ed8f73937
image

猜你喜欢

转载自blog.csdn.net/weixin_34126557/article/details/86815326