質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

891閲覧

実行時間超過 原因は定数倍?

kay_ventris4

総合スコア269

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/06/06 03:07

編集2021/06/06 03:08

#問題
イメージ説明
AtCoder Regular Contest 104 B問題より

#方針
1<=N<=5000という制約から、Sの部分文字列の全列挙自体は計算量は5000*(5000 + 1)//2と見積もられ、実行制限時間2秒を超えることはないと想定されます。しかし、実際に部分文字列を取り出そうとするとスライスの部分で余計な計算量を食うので、あらかじめi番目までにA, T, G, Cが何回登場したかを累積和を用いてA_rec, T_rec, G_rec, C_recに格納しておき、S[i:j]なる部分文字列についてそこから必要な値を用い、その部分文字列に何が何個含まれているかを調べます。そして(Aの個数)=(Tの個数)かつ(Gの個数)=(Cの個数)となれば良いので、それぞれ調べカウントします。

#TLEコード

Python

1from itertools import accumulate 2 3N, S = map(str, input().split()) 4N = int(N) 5 6A_rec = [0] * N 7T_rec = [0] * N 8G_rec = [0] * N 9C_rec = [0] * N 10 11for i in range(N): 12 if S[i] == 'A': 13 A_rec[i] += 1 14 elif S[i] == 'T': 15 T_rec[i] += 1 16 elif S[i] == 'G': 17 G_rec[i] += 1 18 elif S[i] == 'C': 19 C_rec[i] += 1 20A_rec = list(accumulate(A_rec)) 21T_rec = list(accumulate(T_rec)) 22G_rec = list(accumulate(G_rec)) 23C_rec = list(accumulate(C_rec)) 24 25def substring(S): 26 li = [] 27 for i in range(N): 28 for j in range(i + 1, N + 1): 29 if i > 0: 30 li.append([A_rec[j - 1] - A_rec[i - 1], T_rec[j - 1] - T_rec[i - 1], G_rec[j - 1] - G_rec[i - 1], C_rec[j - 1] - C_rec[i - 1]]) 31 elif i == 0: 32 li.append([A_rec[j - 1], T_rec[j - 1], G_rec[j - 1], C_rec[j - 1]]) 33 return li 34 35cnt = 0 36for el in substring(S): 37 if el[0] == el[1] and el[2] == el[3]: 38 cnt += 1 39 40print(cnt)

#質問
substringのところで二重ループを用いましたが、これはNの制約から直接的に実行時間超過に起因しているわけではなさそうであると推察しています。またそれ以外の処理については、全て線形時間で行っているので、これもまた大きな計算量を食っているようには思えません。実行はPypy3とPython3の両方で試しましたが、やはりPythonという言語の定数倍計算の処理の遅さがTLEの原因なのでしょうか。それとも、何か見落としている大きな計算がありますでしょうか。素人質問にて恐縮ですが、お力添え頂ける箇所がございましたら、ご教授のほどよろしくお願い申し上げます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2021/06/06 08:52

画像で質問するより、URLでの質問のほうがいいと思いますよ。
guest

回答3

0

ベストアンサー

私の見る限り、問題は二つあります。

問題1 アルゴリズム
不要な計算が多いと思います。
例: 長さが奇数の時に必要もないのに調べている。
他もいろいろあってアルゴリズムの根本的な見直しをすべきです。
それを角と、この問題のネタバレになるので、まずはご自身で考えてください。

問題2 メモリ割当ての多いこと
S[i]を使うと、新しいstrのインスタンスが作られるので結構時間を使います。
li.appendを使うと、メモリのとりなおしが数回に一回おきるので結構時間を使います。

これらの二つの問題をなくせばかなりスピードアップするでしょう。

投稿2021/06/06 08:11

ppaul

総合スコア24670

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kay_ventris4

2021/06/06 09:11

自己解決の欄にコードは載せましたが、ご教示頂いた通りj-iが奇数になる場合を飛ばし、さらにappendの過程を抜いて直接関数内でカウントすることにより実行時間が最大183msまで削ることができました。後ほどアルゴリズムの自己評価は行いますが、とりあえずこれだけでも大きな成果でした。ありがとうございました。
guest

0

cProfile
https://docs.python.org/ja/3/library/profile.html
とかを使うとどこが遅いかだいたいわかると思いますよ。

この使い方が便利なのではないかと思います。

python -m cProfile [-o output_file] [-s sort_order] (-m module | myscript.py)

ご参考まで。

投稿2021/06/06 03:33

mokemokechicken

総合スコア948

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

リストへのappendを省き、(j - i)が偶数である時のみのアルゴリズムに変更したところ、うまく行きました:

Python

1from itertools import accumulate 2 3N, S = map(str, input().split()) 4N = int(N) 5 6A_rec = [0] * N 7T_rec = [0] * N 8G_rec = [0] * N 9C_rec = [0] * N 10 11for i in range(N): 12 if S[i] == 'A': 13 A_rec[i] += 1 14 elif S[i] == 'T': 15 T_rec[i] += 1 16 elif S[i] == 'G': 17 G_rec[i] += 1 18 elif S[i] == 'C': 19 C_rec[i] += 1 20A_rec = list(accumulate(A_rec)) 21T_rec = list(accumulate(T_rec)) 22G_rec = list(accumulate(G_rec)) 23C_rec = list(accumulate(C_rec)) 24 25def solve(S): 26 cnt = 0 27 for i in range(N): 28 for j in range(i + 1, N + 1): 29 if (j - i) % 2 == 0: 30 if i > 0: 31 if A_rec[j - 1] - A_rec[i - 1] == T_rec[j - 1] - T_rec[i - 1] and G_rec[j - 1] - G_rec[i - 1] == C_rec[j - 1] - C_rec[i - 1]: 32 cnt += 1 33 elif i == 0: 34 if A_rec[j - 1] == T_rec[j - 1] and G_rec[j - 1] == C_rec[j - 1]: 35 cnt += 1 36 return cnt 37 38print(solve(S))

投稿2021/06/06 09:13

kay_ventris4

総合スコア269

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問