华为笔试在线训练-DNA序列问题

题目描述

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

给定一个很长的DNA序列,以及要求的最小子序列长度,研究人员经常会需要在其中找出GC-Ratio最高的子序列。
牛客网链接
https://www.nowcoder.com/practice/e8480ed7501640709354db1cc4ffd42a?tpId=37&tqId=21286&rp=0&ru=/ta/huawei&qru=/ta/huawei/question-ranking
前言

本题中绝大部分的解决方法都是时间复杂度O(m*n),本文提供一种时间复杂度O(m) 空间复杂度为O(n)的方法。(其中m表示DNA序列的长度,n表示子序列的长度),算法思想受左程云《程序员代码面试指南》-“生成窗口最大值数组”和“最大值减去最小值小于或等于num的子数组数量”启发,向牛客网左程云老师表示感谢,跟着老师学了很久,终于感受到了算法构想的进步。

符号说明:
m:序列的总长度;
n: 子序列长度;
first:队列头部元素值(注意是下标不是真实的数值);
size:滑动窗口中元素的个数,其实就是滑动窗口内G和C的总数;
start:最长子序列的第一个元素下标
max:最长子序列的长度
算法流程
建立滑动窗口(双端队列) 滑动窗口大小为n;
遍历DNA序列,窗口向前滑动,当遍历到的元素为'G'||'C'的时候,元素下标从队列尾部进入队列;
当first=i-w的时候,双端队列首部元素出队列;
更新start和max的值;
最后利用substring()进行子序列截取,打印;

当输入为如下序列的时候
TTTTCTGTTAGCGGTCCATCCTACCCCCTAAGAGTATCAGCGCATTAACTGTTGGGTAGACCTATACCGAAC
42
正确输出:TTTCTGTTAGCGGTCCATCCTACCCCCTAAGAGTATCAGCGC
但是截止到目前的算法思路输出:CTGTTAGCGGTCCATCCTACCCCCTAAGAGTATCAGCGCATT
所以要多考虑边界条件

import java.util.*;
import java.io.*;

public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String str;
        int start=0;
        int max=-1;
        while((str=reader.readLine())!=null) {
            int w=Integer.valueOf(reader.readLine());
            LinkedList<Integer> list=new LinkedList<>();
            char temp;
            if(w<1||str.length()<w){
                continue;
            }
            for(int i=0;i<str.length();i++){
                temp=str.charAt(i);
                if(temp=='G'||temp=='C'){
                    list.offerLast(i);
                }
                if((list.size()!=0)&&(i-w==list.peekFirst())){
                    list.pollFirst();
                }
              //  if(i>=w-1){
                if(list.size()!=0){
                    start=list.size()>max?list.peekFirst():start;
                    max=Math.max(max,list.size());
                }
               // }
            }
            int lastIndex=0;
            for(int j=start+w-1;j>=start;j--){
                if(str.charAt(j)=='G'||str.charAt(j)=='C'){
                    break;
                }else{
                    lastIndex++;
                }
            }
            if((start-lastIndex)<0){
                System.out.println(str.substring(0,w));
                continue;
            }
            System.out.println(str.substring(start-lastIndex,start-lastIndex+w));
        }

    }


}
全部评论
#include <iostream> #include <string> using namespace std; int main() { string s; int n; while (cin >> s >> n) { int left = 0, right = 0; double gc_num = 0; double max_ratio = 0; int start = 0; while (right < s.size()) { if (s[right] == 'G' || s[right] == 'C') gc_num++; int len = right-left+1; if (len > n) { if (s[left] == 'G' || s[left] == 'C') gc_num--; left++; } double ratio = gc_num / n; if (ratio > max_ratio) { max_ratio = ratio; start = left; } right++; } cout << s.substr(start, n) << endl; } return 0; }</string></iostream>
1 回复 分享
发布于 2020-07-15 16:14
看了大佬的改进方法,确实给了我启发,为大佬点赞(。ò ∀ ó。)
点赞 回复 分享
发布于 2020-05-16 20:30
这算法改进的真是厉害,目前时间复杂度好低的,确实实用,大佬就是大佬。厉害!厉害(ง •̀_•́)ง
点赞 回复 分享
发布于 2020-05-16 21:11
大佬太厉害了!!解决了我好多问题!!!👍
点赞 回复 分享
发布于 2020-05-16 21:48
赞赞赞!
点赞 回复 分享
发布于 2020-05-16 21:48
太仔细认真了 总结的很到位!!对我醍醐灌顶!!
点赞 回复 分享
发布于 2020-05-16 21:49

相关推荐

我见java多妩媚:大外包
点赞 评论 收藏
分享
6 6 评论
分享
牛客网
牛客企业服务