华为笔试在线训练-DNA序列问题(时间复杂度O(n)目前存在的解题思路中时间复杂度最低)

题目描述

    一个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));
        }
    }
}

你可能感兴趣的:(算法)