java codility training Genomic-range-query

后端 未结 30 2259
悲哀的现实
悲哀的现实 2021-02-01 12:47

The task is:

A non-empty zero-indexed string S is given. String S consists of N characters from the set of upper-case English letters A, C, G, T.

<
相关标签:
30条回答
  • 2021-02-01 13:24

    Here is the solution that got 100 out of 100 in codility.com. Please read about prefix sums to understand the solution:

    public static int[] solveGenomicRange(String S, int[] P, int[] Q) {
            //used jagged array to hold the prefix sums of each A, C and G genoms
            //we don't need to get prefix sums of T, you will see why.
            int[][] genoms = new int[3][S.length()+1];
            //if the char is found in the index i, then we set it to be 1 else they are 0
            //3 short values are needed for this reason
            short a, c, g;
            for (int i=0; i<S.length(); i++) {
                a = 0; c = 0; g = 0;
                if ('A' == (S.charAt(i))) {
                    a=1;
                }
                if ('C' == (S.charAt(i))) {
                    c=1;
                }
                if ('G' == (S.charAt(i))) {
                    g=1;
                }
                //here we calculate prefix sums. To learn what's prefix sums look at here https://codility.com/media/train/3-PrefixSums.pdf
                genoms[0][i+1] = genoms[0][i] + a;
                genoms[1][i+1] = genoms[1][i] + c;
                genoms[2][i+1] = genoms[2][i] + g;
            }
    
            int[] result = new int[P.length];
            //here we go through the provided P[] and Q[] arrays as intervals
            for (int i=0; i<P.length; i++) {
                int fromIndex = P[i];
                //we need to add 1 to Q[i], 
                //because our genoms[0][0], genoms[1][0] and genoms[2][0]
                //have 0 values by default, look above genoms[0][i+1] = genoms[0][i] + a; 
                int toIndex = Q[i]+1;
                if (genoms[0][toIndex] - genoms[0][fromIndex] > 0) {
                    result[i] = 1;
                } else if (genoms[1][toIndex] - genoms[1][fromIndex] > 0) {
                    result[i] = 2;
                } else if (genoms[2][toIndex] - genoms[2][fromIndex] > 0) {
                    result[i] = 3;
                } else {
                    result[i] = 4;
                }
            }
    
            return result;
        }
    
    0 讨论(0)
  • 2021-02-01 13:24

    Here is a C# solution, the basic idea is pretty much the same as the other answers, but it may be cleaner:

    using System;
    
    class Solution
    {
        public int[] solution(string S, int[] P, int[] Q)
        {
            int N = S.Length;
            int M = P.Length;
            char[] chars = {'A','C','G','T'};
    
            //Calculate accumulates
            int[,] accum = new int[3, N+1];
            for (int i = 0; i <= 2; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    if(S[j] == chars[i]) accum[i, j+1] = accum[i, j] + 1;
                    else accum[i, j+1] = accum[i, j];
                }
            }
    
            //Get minimal nucleotides for the given ranges
            int diff;
            int[] minimums = new int[M];
            for (int i = 0; i < M; i++)
            {
                minimums[i] = 4;
                for (int j = 0; j <= 2; j++)
                {
                    diff = accum[j, Q[i]+1] - accum[j, P[i]];
                    if (diff > 0)
                    {
                        minimums[i] = j+1;
                        break;
                    }
                }
            }
    
            return minimums;
        }
    }
    
    0 讨论(0)
  • 2021-02-01 13:25

    Here is my solution. Got %100 . Of course I needed to first check and study a little bit prefix sums.

    public int[] solution(String S, int[] P, int[] Q){
    
            int[] result = new int[P.length];
    
            int[] factor1 = new int[S.length()];
            int[] factor2 = new int[S.length()];
            int[] factor3 = new int[S.length()];
            int[] factor4 = new int[S.length()];
    
            int factor1Sum = 0;
            int factor2Sum = 0;
            int factor3Sum = 0;
            int factor4Sum = 0;
    
            for(int i=0; i<S.length(); i++){
                switch (S.charAt(i)) {
                case 'A':
                    factor1Sum++;
                    break;
                case 'C':
                    factor2Sum++;
                    break;
                case 'G':
                    factor3Sum++;
                    break;
                case 'T':
                    factor4Sum++;
                    break;
                default:
                    break;
                }
                factor1[i] = factor1Sum;
                factor2[i] = factor2Sum;
                factor3[i] = factor3Sum;
                factor4[i] = factor4Sum;
            }
    
            for(int i=0; i<P.length; i++){
    
                int start = P[i];
                int end = Q[i];
    
                if(start == 0){
                    if(factor1[end] > 0){
                        result[i] = 1;
                    }else if(factor2[end] > 0){
                        result[i] = 2;
                    }else if(factor3[end] > 0){
                        result[i] = 3;
                    }else{
                        result[i] = 4;
                    }
                }else{
                    if(factor1[end] > factor1[start-1]){
                        result[i] = 1;
                    }else if(factor2[end] > factor2[start-1]){
                        result[i] = 2;
                    }else if(factor3[end] > factor3[start-1]){
                        result[i] = 3;
                    }else{
                        result[i] = 4;
                    }
                }
    
            }
    
            return result;
        }
    
    0 讨论(0)
  • 2021-02-01 13:25

    This program has got score 100 and performance wise has got an edge over other java codes listed above!

    The code can be found here.

    public class GenomicRange {
    
    final int Index_A=0, Index_C=1, Index_G=2, Index_T=3;
    final int A=1, C=2, G=3, T=4; 
    
    public static void main(String[] args) {
    
        GenomicRange gen = new GenomicRange();
        int[] M = gen.solution( "GACACCATA", new int[] { 0,0,4,7 } , new int[] { 8,2,5,7 } );
        System.out.println(Arrays.toString(M));
    } 
    
    public int[] solution(String S, int[] P, int[] Q) {
    
        int[] M = new int[P.length];
        char[] charArr = S.toCharArray();
        int[][] occCount = new int[3][S.length()+1];
    
        int charInd = getChar(charArr[0]);
    
        if(charInd!=3) {
            occCount[charInd][1]++;
        }
    
        for(int sInd=1; sInd<S.length(); sInd++) {
    
            charInd = getChar(charArr[sInd]);
    
            if(charInd!=3)
                occCount[charInd][sInd+1]++;
    
            occCount[Index_A][sInd+1]+=occCount[Index_A][sInd];
            occCount[Index_C][sInd+1]+=occCount[Index_C][sInd];
            occCount[Index_G][sInd+1]+=occCount[Index_G][sInd];
        }
    
        for(int i=0;i<P.length;i++) {
    
            int a,c,g;
    
            if(Q[i]+1>=occCount[0].length) continue;
    
            a =  occCount[Index_A][Q[i]+1] - occCount[Index_A][P[i]];
            c =  occCount[Index_C][Q[i]+1] - occCount[Index_C][P[i]];
            g =  occCount[Index_G][Q[i]+1] - occCount[Index_G][P[i]];
    
            M[i] = a>0? A : c>0 ? C : g>0 ? G : T;    
        }
    
        return M;
    }
    
    private int getChar(char c) {
    
        return ((c=='A') ? Index_A : ((c=='C') ? Index_C : ((c=='G') ? Index_G : Index_T)));  
    }
    }
    
    0 讨论(0)
  • 2021-02-01 13:25

    In ruby (100/100)

    def interval_sum x,y,p
        p[y+1] - p[x]
    end
    
    def solution(s,p,q)
    
        #Hash of arrays with prefix sums
    
        p_sums = {}
        respuesta = []
    
    
        %w(A C G T).each do |letter|
            p_sums[letter] = Array.new s.size+1, 0
        end 
    
        (0...s.size).each do |count|
            %w(A C G T).each do |letter|
                p_sums[letter][count+1] = p_sums[letter][count] 
            end if count > 0
    
            case s[count]
            when 'A'
                p_sums['A'][count+1] += 1
            when 'C'
                p_sums['C'][count+1] += 1
            when 'G'
                p_sums['G'][count+1] += 1
            when 'T'
                p_sums['T'][count+1] += 1
            end 
    
        end
    
    
    
    
        (0...p.size).each do |count|
    
    
            x = p[count]
            y = q[count]
    
    
            if interval_sum(x, y, p_sums['A']) > 0 then
                respuesta << 1
                next
            end 
    
            if interval_sum(x, y, p_sums['C']) > 0 then
                respuesta << 2
                next
            end 
    
            if interval_sum(x, y, p_sums['G']) > 0 then
                respuesta << 3
                next
            end 
    
            if interval_sum(x, y, p_sums['T']) > 0 then
                respuesta << 4
                next
            end 
    
        end
    
        respuesta
    
    end
    
    0 讨论(0)
  • 2021-02-01 13:26

    This is a Swift 4 solution to the same problem. It is based on @codebusta's solution above:

    public func solution(_ S : inout String, _ P : inout [Int], _ Q : inout [Int]) -> [Int] {
    var impacts = [Int]()
    var prefixSum = [[Int]]()
    for _ in 0..<3 {
        let array = Array(repeating: 0, count: S.count + 1)
        prefixSum.append(array)
    }
    
    for (index, character) in S.enumerated() {
        var a = 0
        var c = 0
        var g = 0
    
        switch character {
        case "A":
            a = 1
    
        case "C":
            c = 1
    
        case "G":
            g = 1
    
        default:
            break
        }
    
        prefixSum[0][index + 1] = prefixSum[0][index] + a
        prefixSum[1][index + 1] = prefixSum[1][index] + c
        prefixSum[2][index + 1] = prefixSum[2][index] + g
    }
    
    for tuple in zip(P, Q) {
        if  prefixSum[0][tuple.1 + 1] - prefixSum[0][tuple.0] > 0 {
            impacts.append(1)
        }
        else if prefixSum[1][tuple.1 + 1] - prefixSum[1][tuple.0] > 0 {
            impacts.append(2)
        }
        else if prefixSum[2][tuple.1 + 1] - prefixSum[2][tuple.0] > 0 {
            impacts.append(3)
        }
        else {
            impacts.append(4)
        }
    }
    
       return impacts
     }
    
    0 讨论(0)
提交回复
热议问题