首页 > 试题广场 >

DNA序列

[编程题]DNA序列
  • 热度指数:123667 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解

一个 DNA 序列由 A/C/G/T 四个字母的排列组合组成。 G 和 C 的比例(定义为 GC-Ratio )是序列中 G 和 C 两个字母的总的出现次数除以总的字母数目(也就是序列长度)。在基因工程中,这个比例非常重要。因为高的 GC-Ratio 可能是基因的起始点。

给定一个很长的 DNA 序列,以及限定的子串长度 N ,请帮助研究人员在给出的 DNA 序列中从左往右找出 GC-Ratio 最高且长度为 N 的第一个子串。
DNA序列为 ACGT 的子串有: ACG , CG , CGT 等等,但是没有 AGT , CT 等等

数据范围:字符串长度满足  ,输入的字符串只包含 A/C/G/T 字母

输入描述:

输入一个string型基因序列,和int型子串的长度



输出描述:

找出GC比例最高的子串,如果有多个则输出第一个的子串

示例1

输入

ACGT
2

输出

CG

说明

ACGT长度为2的子串有AC,CG,GT3个,其中AC和GT2个的GC-Ratio都为0.5,CG为1,故输出CG   
示例2

输入

AACTGTGCACGACCTGA
5

输出

GCACG

说明

虽然CGACC的GC-Ratio也是最高,但它是从左往右找到的GC-Ratio最高的第2个子串,所以只能输出GCACG。    

时间复杂度O(n)2都能通过啊……

while True:
    try:
        a, b = input(), int(input())
        maxStr, maxCnt = a[:b], a[:b].count("C") + a[:b].count("G")
        for i in range(0, len(a) - b):
            if a[i:i + b].count("C") + a[i:i + b].count("G") > maxCnt:
                maxCnt = a[i:i + b].count("C") + a[i:i + b].count("G")
                maxStr = a[i:i + b]
        print(maxStr)
    except:
        break
编辑于 2018-08-29 19:20:57 回复(5)
while True:
  try:
    a,b,c = input(),int(input()),[]
    for i in range(len(a)-b+1):
      if a[i] == "G"&nbs***bsp;"C":
        c.append([a[i:i+b],a[i:i+b].count("C")+a[i:i+b].count("G")])
    c.sort(key = lambda x: x[1], reverse = True)
    print(c[0][0])
  except:
    break

发表于 2020-02-20 20:04:31 回复(2)
import java.util.*;
public class Main {
	public static int GCRatio(String str){
		int count = 0;
		for(int i=0;i<str.length();i++){
			if(str.charAt(i)=='G'||str.charAt(i)=='C'){
				count++;
			}
		}
		return count;
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner scan = new Scanner(System.in);
		while(scan.hasNext()){
			String str = scan.next();
			int n = scan.nextInt();
			String[] strs = new String[str.length()-n];
			LinkedHashMap<String,Integer> map = new LinkedHashMap<String,Integer>();
			//
			for(int i=0;i<str.length()-n;i++){
				strs[i]=str.substring(i, i+n);
				map.put(strs[i], GCRatio(strs[i]));
			}
			Collection<Integer> coll = map.values();
			int value = Collections.max(coll);
			Set<String> set = map.keySet();
			for(String s :set){
				if(map.get(s)==value){
					System.out.println(s);
					break;
				}
			}
		}
	}

} 
大神们,自己机子上运行还可以,为什么总是提示野指针?

发表于 2016-06-13 16:08:43 回复(0)
// 一个 DNA 序列由
// A/C/G/T 四个字母的排列组合组成。
// G 和 C 的比例(定义为 GC-Ratio )是序列中 G 和 C 两个字母的总的出现次数除以总的字母长度)。
// 给定一个很长的 DNA 序列,以及限定的子串长度 N ,
// 请帮助研究人员在给出的 DNA 序列中从左往右找出 GC-Ratio 最高且长度为 N 的第一个子串。
// DNA序列为 ACGT 的子串有: ACG , CG , CGT 等等,但是没有 AGT , CT 等等

#include<stdio.h>
#include<string.h>

struct {
    float Ratio;//子串对应的GC-Ratio
    int gc_cnt;//GC个数
    int sn;//出现的序号
    char str_child[1000];//子串
} data[1000], temp;

int main() {
    char str[1000];
    int num;
    scanf("%s", str);
    scanf("%d", &num);
    int len = strlen(str);
    int h = 0;
    int k = 0;
    for (int i = 0; i < len - num + 1; i++) {
        k = 0;
        //子串是,从第1个向后数1个,从第2个向后数1个,从第3个向后数1个

        for (int j = i; j < i + num; j++) {
            data[h].str_child[k++] = str[j];  //存子串
        }
        data[h].sn = h;
        h++;//子串个数
    }
    //统计每个子串的GC个数
    for (int i = 0; i < h; i++) {
        //遍历子串,计算GC-Ratio
        for (int j = 0; j < num; j++) {
            if ((data[i].str_child[j] == 'G') || data[i].str_child[j] == 'C') {
                data[i].gc_cnt += 1;
            }
        }
    }
    //计算GC-Ratio
    for (int i = 0; i < h; i++) {
        data[i].Ratio = (float)data[i].gc_cnt / num;
    }
    for (int i = 0; i < h; i++) {
        for (int j = i + 1; j < h; j++) {

            if (data[i].Ratio > data[j].Ratio) {
                temp = data[i];
                data[i] = data[j];
                data[j] = temp;
            }
        }
    }
    //比较最大值和所有的值是否最大,如果有和最大值一样的值,输出最先出现的那个
    int outNum = h - 1;
    for (int i = 0; i < h; i++) {
        if (data[outNum].Ratio == data[i].Ratio) {
            //输出序号最小的那个
            if (data[i].sn < data[outNum].sn) {
                outNum = i;
            }
        }
    }
    printf("%s",data[outNum].str_child);

    return 0 ;
}
发表于 2022-04-13 22:10:42 回复(0)
我女朋友说这题目给的不对, 应该叫RNA(或者polynucleotide), DNA 是双链。
发表于 2022-03-01 01:08:03 回复(0)

用的python3计算,思路及代码如下:

  1. 根据需求,输出字符串长度已经规定了,如果要 GC-Ratio最高,那么则代表要求输出字符串中C和G的数量最多;
  2. 因为是要在输入的字符串中找到一段长度为N的字符串,可以遍历所有的长度为N的字符串并存放进一个列表中,我定义为GC_list;
  3. 对于GC_list列表中的每一个字符串目前都是满足长度为N的要求了,那么下一步就是选出列表中含有最多的C、G的字符串出来;
  4. 再定义一个空列表num_list用于存放GC_list中各个字符串含有C、G的数量,即遍历GC_list中每一个字符串,判断是否含有C、G,含有则conunt+1,count追加进入num_list,则GC_list中字符串的下标与num_list中数字的下标一一对应;
  5. 通过max取得num_list中的最大值,再通过index判断最大值的下标,这个下标在GC_list中对应的字符串即是我们需要的字符串,打印输出即可。
def func(s,n):
    GC_list=[]
    for i in range(len(s)-n+1): # 考虑输出字符串长度n,不能循环至末尾
        GC_str=s[i:i+n]
        GC_list.append(GC_str) # 遍历完所有长度为n的字符串,追加进入GC_list列表
        pass
    num=[]
    for j in range(len(GC_list)): # 遍历GC_list列表中每一个字符串
        count=0
        for a in GC_list[j]: # 对于每一个字符串而言,判断C、G是否存在,存在则+1
            if a=="C":
                count+=1
                pass
            elif a=="G":
                count+=1
                pass
            pass
        num.append(count) # 把每一个字符串中C、G的数量追加进num列表
        pass
    num_max=max(num) # 求num列表最大值
    res_num=num.index(num_max) # 求最大值对应的下标
    return GC_list[res_num] # GC_list中对应下标的字符串即是所需字符串
    pass
while True:
    try:
        s=str(input())
        n=int(input())
        print(func(s,n))
        pass
    except:
        break

发表于 2021-12-20 23:27:20 回复(0)
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()) {
            String DNA = sc.next();
            int N = sc.nextInt();
            double n = N;
            int index = -1;
            double max = 0;
            for(int i = 0; i < DNA.length() - N + 1; i++) {
                double num = ratio(DNA.substring(i, i + N)) / n;
                if(num > max) {
                    max = num;
                    index = i;
                }
            }
            System.out.println(DNA.substring(index, index + N));
        }
    }
    public static double ratio(String s) {
        s = s.replaceAll("[AT]","");
        return s.length();
    }
}

发表于 2021-11-02 20:18:39 回复(0)
let str = readline()
let n = parseInt(readline())
let max = 0
let maxStr = ''
for(let i=0;i<=(str.length-n);i++){
    let subStr = str.slice(i,i+n)
    let filterStr = subStr.replace(/[^CG]/g,'')
    let ratio = filterStr.length/subStr.length
    if(ratio>max){
        max = ratio
        maxStr = subStr
    }
}
print(maxStr)

发表于 2021-07-16 00:03:30 回复(0)
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
int main()
{
    string s;
    int x;
    while(cin>>s) {
        cin>>x;
        int index=-1;
        int max_count=0;
        int cur=0;
        int len=s.size();
        int i;
        for(i=0;i<x && i<len;++i) {
            if(s[i]=='G' || s[i]=='C') {
                ++cur;
            }
        }
        max_count=cur;
        index=0;
        while(i<len) {
            if(s[i-x]=='G' || s[i-x]=='C')
                --cur;
            if(s[i]=='G' || s[i]=='C')
                ++cur;
            if(cur>max_count) {
                max_count=cur;
                index=i-x+1;
            }
            ++i;
        }
        cout<<s.substr(index,x)<<endl;
    }
    return 0;
}

发表于 2021-06-28 14:42:48 回复(0)
while(True):
    try:
        # 输入处理
        L = input()
        N = int(input())
        # 全局变量max比率和最大比率对应的子串
        max_ratio = 0
        L_max = []
        # 核心处理
        for i in range(0,(len(L)-N+1)):  # 第一层循环是按位置进行滑窗推进
            num = 0
            if 'C' in L[i:i+N] and 'G' in L[i:i+N]:  # 如果C和G同时都在里面的话,就进去该滑窗去计算比率
                for j in L[i:i+N]:    # 第二个循环是滑窗内进行统计比率
                    if j == 'C' or j == 'G':  # 只C G时就+1
                        num += 1
                    else:
                        continue
                if max_ratio < num / N:  # 跳出第二层循环,判断是否最大,是的话就保存
                    max_ratio = num / N
                    L_max.clear()
                    L_max.append(L[i:i+N])
            else:  # 如果不在,那么就跳过到下一个位置
                continue
        # 输出处理,第一句列表转字符串的万金油公式,如果列表元素不是字符,在前面多加一句 L=map(str,L),大家一定要会用
        L_max = ''.join(L_max)
        print(L_max)
    except:
        break
发表于 2021-06-13 23:19:11 回复(0)
/**
 * 本人使用了比较直接的办法,就是挨个遍历,算出来每个子串的CG比例,
 * 然后找到第一个出现的比例最大的子串的位置。可能时间复杂度较大,
 * 希望网友提出改进意见。
 *
 */

import java.util.Scanner;

public class Main {
    public static void main(String args[]) {
        Scanner s = new Scanner(System.in);
        while(s.hasNext()) {
            String str = s.next();
            int n=s.nextInt();
            int length=str.length();
            double[] ratio=new double[length-n+1];  //用数组来存储每个子串的CG比例
            for(int i=0;i<length-n+1;i++){
                ratio[i]=calculate(str.substring(i,i+n)); //计算每个子串的CG比例
            }
            double max=0;
            for(int i=0;i<length-n+1;i++){
                if(max<ratio[i]){
                    max=ratio[i];
                }
            }
            int flag=-1;
            for(int i=0;i<length-n+1;i++){
                if(max==ratio[i]){
                    flag=i;   //找到第一个比例最大的子串。
                    break;
                }
            }

            System.out.println(str.substring(flag,flag+n));
            }
        }


    private static double calculate(String str){
         char[] ch=str.toCharArray();
         double num=0;
         double d=str.length();
         for(int i=0;i<ch.length;i++){
             if(ch[i]=='G'||ch[i]=='C'){
                 num++;
             }
         }
      return  num/d;
    }
}








发表于 2021-04-05 20:04:00 回复(0)
记子串长度为n,滑动窗口求解:首先求第一个窗口大小为n的子串的CG比例,然后开始滑动窗口,每次根据出去的左边界字符和新进的右边界字符来更新CG比例,如果比例变高了就更新子串,否则不更新。
seq = input().strip()
n = int(input())
# 初始子串和CG比例
res = seq[:n]
count = res.count('C') + res.count('G')
ratio = count / n
for i in range(1, len(seq) - n):
    if seq[i - 1] == 'C'&nbs***bsp;seq[i - 1] == 'G':
        count -= 1
    if seq[i + n - 1] == 'C'&nbs***bsp;seq[i + n - 1] == 'G':
        count += 1
    # 如果CG比例变高了(等于也不行),就更新子串和比例
    if count / n > ratio:
        res = seq[i:i + n]
        ratio = count / n
print(res)

编辑于 2021-04-02 11:12:20 回复(0)
Java:
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {
            String s = sc.nextLine();
            int len = sc.nextInt();
            int index = 0, max = 0;
            for (int i = 0; i < s.length() - len; i++) {
                int count = 0;
                for (int j = i; j < i + len; j++) {
                    if (s.charAt(j) == 'G' || s.charAt(j) == 'C') count++;
                }
                if (max < count) {
                    max = count;
                    index = i;
                }
            }
            System.out.println(s.substring(index, index + len));
        }
    }
}

C++:
#include<iostream>
using namespace std;
int main() {
    string str;
    int len;
    while (cin >> str >> len) {
        int index = 0, max = 0;
        for (int i = 0; i <= str.size() - len; ++i) {
            int counts = 0;
            for (int j = i; j < i + len; ++j) {
                if (str[j] == 'G' || str[j] == 'C') counts++;
            }
            if (counts > max) max = counts, index = i;
        }
        cout << str.substr(index, len) << endl;
    }
    return 0;
}

C:
#include<stdio.h>
#include <string.h>
#define SIZE 4096
int main() {
    char str[SIZE] = {0};
    int len;
    while ((scanf("%s %d", str, &len)) != EOF) {
        char tmp[SIZE] = {0};
        int index = 0;
        for (int i = 0, max = 0; i <= strlen(str) - len; ++i) {
            int counts = 0;
            for (int j = i; j < i + len; ++j) {
                if (str[j] == 'G' || str[j] == 'C') counts++;
            }
            if (counts > max) max = counts, index = i;
        }
        strncpy(tmp, &str[index], len);
        printf("%s\n", tmp);
        memset(str, 0, SIZE);
    }
    return 0;
}


发表于 2021-01-30 17:39:16 回复(0)
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            String input = scanner.next();
            int size = scanner.nextInt();
            System.out.println(findMaxGC(input,size));
        }
    }
    public static String findMaxGC(String input, int size){
        String potentialResult = "";
        int currentGCcount = 0;
        for (int i = 0; i <= input.length() - size; i++){
            List<String> sub = Arrays.asList(input.substring(i,i+size).split(""));
            int Gcount = Collections.frequency(sub,"G");
            int Ccount = Collections.frequency(sub,"C");
            if (Gcount == size/2 && Ccount == size/2){
                return String.join("",sub);
            }
            if (currentGCcount < Gcount+Ccount){
                currentGCcount = Gcount+Ccount;
                potentialResult = String.join("",sub);
            }
        }
        return potentialResult;
    }
}

发表于 2021-01-27 18:32:29 回复(0)
while True:
    try:
        string, num = input().strip(), int(input().strip())
        C_and_G_counts = []
        for i in range(0, len(string)-num+1):
            sub_str = string[i:i+num]
            C_and_G_counts.append(sub_str.count('C') + sub_str.count('G'))
        index = C_and_G_counts.index(max(C_and_G_counts))
        print(string[index:index+num])
    except:
        break
        

编辑于 2020-12-09 15:55:41 回复(0)
while True:
    try:
        a = input()
        b = int(input())
        char = a[:b]
        ra = char.count('C')+char.count('G')
        for i in range(1,len(a)-b+1):
            if a[i:i+b].count('C')+a[i:i+b].count('G') > ra:
                char = a[i:i+b]
                ra = char.count('C')+char.count('G')
        print(char)
    except:
        break

发表于 2020-11-06 12:11:59 回复(0)
小伙伴注意了,题目有问题。
题意要求最小长度,实际测试用例要求固定长度,因此符合题意的不符合测试用例
因此没通过的不必介怀。

符合测试用例的
#include <iostream>
#include <string>
#include <deque>

using namespace std;

int Count(const string &s)
{
    int cnt = 0;
    for(auto x : s)
        if(x == 'G' || x == 'C')
            cnt++;
    return cnt;
}

string FindSub(const string &s, int n)
{
    string sub = s.substr(0, n);
    int cnt = Count(sub);
    int max = cnt, mark = 0;
    deque<char> que(sub.begin(), sub.end());
    for(int i = n; i < s.size(); i++)
    {
        
       if(que.front() == 'G' || que.front() == 'C')        
            cnt--; 
        que.pop_front();
        char ch = s[i];
        que.push_back(ch);

        if(ch == 'G' || ch == 'C')
            cnt++;
        if(cnt > max)
        {
            max = cnt;
            mark = i - n + 1;
        }
    }
    return s.substr(mark, n);
}

int main()
{
    string s;
    int n;
    while(cin >> s >> n)
        cout << FindSub(s, n) << endl;
}


符合题意的
#include <iostream>
#include <string>
#include <deque>
#include <vector>

using namespace std;

int Count(const string &s)
{
    int cnt = 0;
    for(auto x : s)
        if(x == 'G' || x == 'C')
            cnt++;
    return cnt;
}
//题意为最短长度n,实测为固定长度n
string FindSub(const string &s, int n, double& percent)
{
	percent = 0;
	string sub = s.substr(0, n);
    int cnt = Count(sub);
    int max = cnt, mark = 0;
    deque<char> que(sub.begin(), sub.end());
    for(int i = n; i < s.size(); i++)
    {
        
       if(que.front() == 'G' || que.front() == 'C')        
            cnt--; 
        que.pop_front();
        char ch = s[i];
        que.push_back(ch);

        if(ch == 'G' || ch == 'C')
            cnt++;
        if(cnt > max)
        {
            max = cnt;
            mark = i - n + 1;
        }
    }
	percent = (double)max / n;
    return s.substr(mark, n);
}

bool IsEqual(double a, double b)
{
	if ((a - b >= -0.000001) && (a - b <= 0.000001))
		return true;
	else
		return false;
}

string FindMax(const string &s, int n)
{
	vector<string> res;
	vector<double> percent(s.size() - n + 1);
	for (int i = n; i <= s.size(); i++)
		res.push_back(FindSub(s, i, percent[i - n]));
	double max = percent[0];
	string ret = res[0];
	for (int i = 1; i < res.size(); i++)
	{
		if (IsEqual(percent[i], max))
			ret = res[0] < res[i] ? res[0] : res[i];
		else if (max < percent[i])
		{
			max = percent[i];
			ret = res[i];
		}
	}
	return ret;
}

int main()
{
    string s;
    int n;
    while(cin >> s >> n)
        cout << FindMax(s, n) << endl;
}


发表于 2020-10-22 21:58:58 回复(0)
因为用的是python,总的来说两种思路:
1、利用序列的count函数计算每个小片段G和C的个数,取最大即可;
2、每次直接使用python的函数总感觉在犯罪,下面分享一个正常思路的解法,有点动态规划的意思,利用一个滚动数组记录,滚动数组dp长度为题目要求小片段的长度l。
dp[0-l]代表小片段包含C和G的个数,当然了,每次dp[-1]代表长度为l的子串包含的G和C的总数。
假设原序列 AACTGTGCACGACCTGA, 小片段长度为5,初始化,dp为前五个字符的G和C的总数,即AACTG对应的dp为[0,0,1,1,2],当进行下一个片段(ACTGT)转移时,即索引从0-4的片段过渡到1-5的片段,这时候变化是:去掉了s[0]但是增加了s[5],又因为dp[4]存的是0-4片段G和C的总数,所以下一个dp[4]存的是1-4片段总数 + 第5个字符是否是G或C - 第0个字符是否是G或C,代码如下:


其中lcsdp是动态规划思想的函数,lcscount是使用了python的count函数的版本
def lcsdp(s, l):
    if len(s) <= l: return s
    slen = len(s)
    dp = [0]*l
    for i in range(l):
        dp[i] = dp[i-1] + (s[i] == 'G' or s[i] == 'C') # python支持负索引,dp[-1]有意义
    mxr, mxindex = dp[l-1], 0
    for i in range(l, slen):
        dp = dp[:l-1] + [dp[-1] + (s[i] == 'G' or s[i] == 'C') - (s[i-l] == 'G' or s[i-l] == 'C')]
        if dp[-1] > mxr:
            mxr = dp[-1]
            mxindex = i-l+1
    return s[mxindex:mxindex+l]
def lcscount(s, l):
    if len(s) <= l: return s
    slen = len(s)
    mxr, mxindex = 0, 0
    for i in range(slen-l+1):
        stmp = s[i:i+l]
        tmpr = stmp.count('G') + stmp.count('C')
        if tmpr > mxr:
            mxr = tmpr
            mxindex = i
    return s[mxindex:mxindex+l]
while True:
    try:
        s, l = input(), int(input())
        print(lcsdp(s, l))
    except:
        break


编辑于 2020-08-26 10:51:26 回复(0)
while True:
    try:
        string,n=input(),int(input())
        tmp,cnt=[],[]
        for i in range(0,len(string)-4):
            tmp.append(string[i:i+n])
            cnt.append(tmp[i].count('G')+tmp[i].count('C'))
        print(tmp[cnt.index(max(cnt))])
    except:
        break

发表于 2020-07-19 15:40:25 回复(0)
提供一种O(n)python解法
while True:
    try:
        s, n, GC, max_len = input(), int(input()), [], 0
        for i in range(len(s)-n+1):
            if i == 0:
                length = s[:n].count("G")+s[:n].count("C")
            else:
                if s[i+n-1] == 'G' or s[i+n-1] == 'C':
                    length += 1
            if length > max_len:
                GC.append(s[i:i+n])
                max_len = length
            if s[i] == 'G' or s[i] == 'C':
                length -= 1
        print(GC[-1])
    except:
        break


编辑于 2020-07-12 05:25:15 回复(1)