高速解と愚直解をぶつける
もっともらしい証明だけで実装ミスは消えません。小さな入力で確実に正しい愚直解と比較し、最小の反例を探します。
言語:Python / 計算量:テスト回数 × 愚直解コスト
考え方
- 小さい制約の愚直解を独立に書きます。
- 乱数の種を固定し、再現可能にします。
- 不一致の入力を保存し、要素を削って原因を絞ります。
具体例
ペアの和を数える高速解では「自分自身を数える」「2倍数える」が典型のバグ。愚直な i<j と比較します。
実装
import random
from collections import Counter
rng=random.Random(0)
def fast(a,k):
c=Counter();ans=0
for x in a:
ans+=c[k-x];c[x]+=1
return ans
for _ in range(100):
a=[rng.randrange(5) for _ in range(8)];k=rng.randrange(9)
slow=sum(a[i]+a[j]==k for i in range(len(a)) for j in range(i+1,len(a)))
assert fast(a,k)==slow,(a,k)
print("OK")注意する条件
ランダムテストが通っても正しさの証明にはなりません。最大値・0・同値・境界の手動テストも必要です。
確認問題
[2,2,2] で和4となる i<j の組数は?
解答と理由
3
添字の組は(0,1),(0,2),(1,2)です。
実装課題
講義の fast で c[x]+=1 を ans+=c[k-x] より前へ移したバグ版を作り、a=[2], k=4 で結果を出す。なぜ誤るか説明。
出力:
1参考実装
from collections import Counter
a=[2];k=4;c=Counter();ans=0
for x in a:
c[x]+=1
ans+=c[k-x]
print(ans)
# 自分自身を数えてしまう。正解は0。