python3 において
n = int(input())
count=0
if n>=3:
for i in range(1,n+1):
for j in range(i,n+1):
for k in range(j,n+1):
if k<i+j:
count+=1
else:
break
print(count)
else:
print(0)
と書いてみましたが、
python3はforループのネストが遅いとネットにでていたので
itertoolsを使って書き直したいのですが、range()において
jの初期値i, kの初期値j,を上手く表現できません。
どなたかご教示ください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/06/26 05:57
2017/06/26 06:16

回答2件
0
ベストアンサー
Python
1for i in range(1,n+1): 2 for j in range(i,n+1): 3 for k in range(j,n+1): 4 ...
の部分を
Python
1import itertools 2for i,j,k in itertools.combinations_with_replacement(range(1,n+1), 3): 3 ...
に置き換えることができます。
【追記】
上記でパフォーマンスがでないようですので・・改善案を書いておきます。
とりあえず 質問での3重ループの一番内側のループは、k<i+j
が成り立つ k
をカウントしているだけですので、この部分をループではなく計算で求めるようにするとループの回数を大幅に少なくすることができます。
Python
1n = 1000 2count = 0 3for i in range(1,n+1): 4 for j in range(i,n+1): 5 count += min(i,n-j+1) 6print(count)
内包表記だとこんなかんじ
Python
1n = 1000 2ret = sum([min(i,n-j+1) for i in range(1,n+1) for j in range(i,n+1) ])
投稿2017/06/25 23:32
編集2017/06/26 04:52総合スコア15898
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/06/26 01:58 編集

0
Python のコードを速くするには、とにかく実行する「Pythonの文」を少なくする。
アルゴリズム的に、ループの回数を小さくする、です。
Python
1from datetime import datetime 2 3start = datetime.now() 4n = 1000 5count=0 6for i in range(1,n+1): 7 for j in range(i,n+1): 8 for k in range(j,n+1): 9 if k<i+j: 10 count+=1 11 else: 12 break 13print(count) 14print(datetime.now() - start) # かかった時間
に対して
Python
1from datetime import datetime 2import itertools 3 4start = datetime.now() 5n = 1000 6count=0 7 8for i,j,k in itertools.combinations_with_replacement(range(1,n+1), 3): 9 count+=1 10print(count) 11print(datetime.now() - start)
は最後の k
のループの範囲が問題で、 i+j
と等しくなった時に、 k
に関するループを抜ければ済むはずなのにそれができない点です。
その分だけ余計にループを回さないといけません。
n=1000の場合で、手元のマシンだと25%ほど遅くなります。
n=1500にすると、ループが増える割合が大きくなって、50%ほど遅くなります。
「ループの回数」の増加分が、「Pythonの文」が減少分に対して見合ってないのです。そして n
が大きくなればなるほどその傾向が大きくなります。
最初のコードで、無駄な部分は if k<i+j:
の部分です。 k
が i+j
に到達したらループを抜けるのですから、これはループの範囲として書いてしまえばいいです。
Python
1from datetime import datetime 2 3start = datetime.now() 4n = 1000 5count=0 6for i in range(1,n+1): 7 for j in range(i,n+1): 8 for k in range(j, min(n+1, i+j)): 9 count+=1 10print(count) 11print(datetime.now() - start)
n
か i+j-1
のうち小さい方までループすればいいのでこう書けます。
これで if k<i+j:
や break
の実行が無くなるので、実行時間は半分ぐらいです。
そして、Python3系では、forループは十分に速くなっていて、メモリを使わずに書こうとした場合は、これが一番よいと思っています。(もっと良い解が出てくると私も嬉しいです)
実はメモリを潤沢に使っていいなら、内包表記でリストを生成して長さを調べるのが最速です。リストの中身は何でもいいです。
Python
1from datetime import datetime 2 3start = datetime.now() 4n = 1000 5print(len([1 for i in range(1,n+1) for j in range(i,n+1) for k in range(j, min(n+1, i+j))])) 6print(datetime.now() - start)
これは上のソースの半分ぐらい。最初のソースの1/4ぐらいです。
ただしメモリは使います。n=1000で600MB、n=1500で2.5GBぐらい使います。
ループが大きくなるなら現実的ではないかもしれませんが、ループの回数の上限がしっかり分かっているなら、往々にして「リストを作ってしまう」のがPyhtonでは最速だったりします。
投稿2017/06/26 02:57
総合スコア11299
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。