あけましておめでとうございます。

年末に投稿しようとしてた記事ですが年末はなんだかんだで忙しくて、年明けちゃいました。

Lesson5になります。ちょっとはまってます。面白いです。

でも、やんなきゃいけないことがたまりにたまっているので、あんまり時間かけないようにします。

 

 

1、PassingCars

 

1と0のペアのカウント。

最初はsumを使っていましたが、やっぱりsumは走査的な処理なので使っちゃダメみたいです。

def solution(A):
    n_A = len(A)
    count = 0
    sum1 = sum(A)
    for i in range(n_A):
        a = A[0]
        del A[0]

        if  a == 0:
            count += abs(a*(n_A-i-1) - sum1)
            print(count)
        else:
            sum1 -= 1
    return count

 

これで60%。

TIMEOUTとペアが多すぎたときに-1を返す処理を入れてないといわれました。

で、stackoverflowを参考にした、逆から配列を読みだせばsumを使わなくてよいプログラムがこちら。

 

def solution(A):
    count = 0
    n_A = len(A)
    one = 0
    for i in range(n_A-1, -1, -1):
        if count > 1000000000:
            return -1
        a = A[i]
        if  a == 0:
            count += one
            print(count)
        else:
            one += 1
    return count

 

これで100%。なるほど~って感じです。

 

 

2、GenomicRangeQuery

 

今度はDNAシークエンサーのお話

A ,C, G, Dの優先度で、ある区間にある塩基の中で一番優先度が高い塩基を配列に保存して返します。

def solution(S, P, Q):
    M = []
    n_Q = len(Q)
    for l in range(n_Q):
        m=4
        for i in range (P[l],Q[l]+1):
            if S[i] == "A":
                m = 1
                break
            elif S[i] == "C":
                m = 2
            elif S[i] == "G"and m == 4 :
                m = 3
        M.append(m)
    return M

 

これだと62%。

ネットに転がっているのをいくつか試しましたけど同じ62%になりました。

問題は調べる区間数が多くなると、毎回走査的な処理を行わなければならなくなることです。

なんで、与えられた配列の最初から最後まで流して、すべてのタイミングでこれまでどの塩基が何個表れか配列に保存しておきます。

で、調べたい区間のはじめと終わりで各塩基の今までの出現数を引き算すれば、何個塩基があるかわかるという算段です。

で、そのプログラムがこちら

def solution(S, P, Q):
    A_count = [0]
    C_count = [0]
    G_count = [0]
    T_count = [0]
    a = 0
    c = 0
    g = 0
    t = 0
    n_S = len(S)
    n_Q = len(Q)
    impacts = []
    for i in range(n_S):
        if S[i] == "A":
            a += 1
        elif S[i] == "C":
            c += 1
        elif S[i] == "G":
            g += 1
        elif S[i] == "T":
            t += 1
        A_count.append(a)
        C_count.append(c)
        G_count.append(g)
        T_count.append(t)
    for i in range(n_Q):
        if A_count[Q[i]+1] - A_count[P[i]] >0:
            impacts.append(1)
        elif C_count[Q[i]+1] - C_count[P[i]] >0:
            impacts.append(2)
        elif G_count[Q[i]+1] - G_count[P[i]] >0:
            impacts.append(3)
        elif T_count[Q[i]+1] - T_count[P[i]] >0:
            impacts.append(4)
    return impacts

 

これで100%でした。

なんの処理がたくさん行われるか考えるのがこの問題で得る知見みたいですね。

ふつうにプログラミングの勉強になってる笑。

 

 

3、MinAvgTwoSlice

 

今回のお話は配列のいろいろな枠で平均をとって、一番平均値が小さい枠の最初のインデックスはどこかという問題。

全部の枠組みなんて計算したら、とてもじゃないけど時間がかかってしょうがないじゃんと思ったら、最小になるのは2つの枠組みか3つ枠組みしかないそうです。

なぜかというと、実験とかする人ならわかると思うんですけど、平均ってとればとるほど全体の平均値に近づいていきますよね。平均値が平均された要素よりも尖った値(より小さい値、より大きい値)をとることはないんです。

で、2と3よりも大きい枠組みは、結局2の枠組みの平均値と3の枠組みの平均値を要素として平均をとってるだけなのでそれ以上尖った値にならないということですね。

そんな気はしてたんだよな笑。

 

def solution(A):
    # write your code in Python 3.6
    min_idx = 0
    min_value = 100
    
    for idx in range(0, len(A)-1):
        if (A[idx] + A[idx+1])/2.0 < min_value:
            min_idx = idx
            min_value = ((A[idx] + A[idx+1])/2.0)
            
        if idx < len(A) -2 and (A[idx] + A[idx+1] + A[idx + 2])/3.0 < min_value:
            min_idx = idx
            min_value = (A[idx] + A[idx+1] + A[idx + 2])/3.0 
    return min_idx

 

 

 

4、CountDiv

 

ただの植木算と思ったのですが、AがKで割り切れないときの処理がてこずりました。

def solution(A,B,K):
    Dif = B - A
    quotient = Dif /  K
    remainder = 0
    if A % K == 0:
        Answer = (B - A)/K + 1
    else:
        Answer  = (B - (A - A % K))/K
    return int(Answer)

 

これで100%です。

 

インターン応募のための勉強としてやっていましたが、ESとかも書かなくちゃいけないような感じになってきたのでcodilityはとりあえずここでやめにしておきます。

ただ、結構勉強になるなって感じましたので、余裕があったらまた再開してもいいかもしれませんね。

勉強してみた感想はコーディング自体はすごく簡単だし、問題も高校入試レベルだけど、機械計算させる前に自分の頭で機械的に優しい計算方法を考えなきゃいけないテストだとわかりました。

あと、自分で計算している気づくけど、コードを書いているとついつい見落としてしまう例外的な事例も対応できるようにするのも大切だと思います。

 

 

それでは。