1. [2,7,11,15], 9 -> [0,1]
  2. [3,2,4], 6 -> [1,2]
  3. [3,3], 6 -> [0,1]
  4. [-1,-2,-3,-4], -7 -> [2,3]
  5. [1,5,3,8,2], 10 -> [3,4] (8+2)
  6. [0,4,3,0], 0 -> [0,3]
コース一覧
コンピューターサイエンス入門:理論編
二数の和 (map で O(n))

コンピューターサイエンス入門:理論編

2 進数、論理演算、ビット演算、データ構造、計算量、メモリモデルなど、プログラミングの土台となるコンピュータサイエンスの理論知識を学べるコースです。プログラミングを始めたばかりの学習者や、CS の体系的な土台を作りたい現役エンジニアを対象としています。約 13 時間 (1 日 30 分 × 26 日) で 53 レッスンを修了でき、修了後はコードのパフォーマンスや設計判断の根拠を理解した上で実装できるようになります。

1
2進数とビット演算
01. 2進数から10進数への変換5分
02. 10進数から2進数への変換5分
03. ビットAND演算でフラグ判定5分
04. OR / XOR でフラグを操作する5分
05. popcount で 1 のビット数を数える5分
06. シフト演算で 2 倍 / 半分5分
07. 16 進数から 10 進数への変換5分
08. 第 1 章まとめクイズ5分
2
文字コードと真偽値ロジック
01. 文字 → ASCII コード5分
02. コード → 文字5分
03. UTF-8 のバイト長を返す5分
04. AND / OR の真理値表5分
05. NOT / XOR の真理値表5分
06. 含意 (→) を AND/OR/NOT で表現5分
07. ド・モルガンの法則5分
08. 第2章まとめクイズ5分
3
計算量とBig-O
01. forループの実行回数を返す5分
02. 入れ子ループの実行回数5分
03. 線形探索 (O(n))5分
04. 二分探索 (O(log n))5分
05. バブルソート5分
06. 配列の最大と最小5分
07. 累積和で範囲合計5分
08. 第3章まとめクイズ5分
4
データ構造 (基本)
01. スタック (push/pop) を実装する5分
02. キュー (enqueue / dequeue) を実装する5分
03. カッコのバランス判定 (スタック応用)5分
04. set で重複を除去する5分
05. map で出現回数を数える5分
06. 二数の和 (map で O(n))5分
07. アナグラム判定5分
08. 第 4 章クイズ — データ構造 (基本)5分
5
ファイル / メモリ / IO 概念
01. バイト → KB 変換5分
02. ディスクサイズフォーマット5分
03. キャッシュヒット率5分
04. LRU 簡易シミュレーション5分
05. エンディアンの入れ替え (uint32)5分
06. バッファ範囲チェック5分
07. 第5章まとめクイズ5分
6
ネットワークと符号化
01. Base64 エンコード後の長さ計算5分
02. URL エンコード対象文字数5分
03. IPv4 アドレスを 32bit 整数に変換5分
04. 32bit 整数を IPv4 アドレスに変換5分
05. CIDR プレフィックスからネットマスクを作る5分
06. 単純チェックサム5分
07. 第6章まとめクイズ5分
7
設計と DB 基礎
01. 重複データを 1NF に変換 (フラットなリスト化)5分
02. キーで join (map 利用)5分
03. 残高転送のトランザクション風処理5分
04. CAP の availability 模擬5分
05. URL ルーティング5分
06. 疎結合と密結合 — 依存性注入で設計を変える12分
07. コース総まとめクイズ5分

二数の和 (map で O(n))

100 件で 4950 回、1 万件で 5000 万回

配列の中から、足して目標の数になる 2 つを見つけたい。まず思いつくのは総当たりです。1 番目と 2 番目、1 番目と 3 番目、と全部の組み合わせを試します。

組み合わせの数は、はっきり数えられます。

Python

n = 100 print(n * (n - 1) // 2) # 4950 n = 10000 print(n * (n - 1) // 2) # 49995000

100 件なら 4950 回の足し算と比較で、これは一瞬です。1 万件になると約 5000 万回で、目に見えて待たされます。10 万件なら 50 億回で、もう終わりません。件数が 10 倍になるたび、比較は 100 倍。入れ子のループを書いた時点で、この増え方が確定します。

相方の値は、引き算だけで分かっている

総当たりが無駄なのは、探す相手が分かっているのに、総当たりしている ところです。

目標が 10 で、いま見ている値が 3 なら、必要な相方は 7 以外にありえません。

Python

target = 10 v = 3 print(target - v) # 7

つまり本当に知りたいのは「この配列のどこかに 7 があるか」だけです。問題が「全部の組み合わせを試す」から「ある値が既に出てきたか」に置き換わりました。ここが分かれ目です。

見た値を控えておけば、探さなくて済む

「既に出てきたか」を配列に聞くと、また先頭からなめることになります。前回使った、値を渡せば一定時間で答えが返る入れ物を使います。

置くものが少しだけ違います。今回はキーを 見た値、中身を その値があった位置 にします。位置まで覚えておかないと、見つかったときに何番目だったかを答えられないからです。

Python

seen = {} seen[3] = 0 # 値 3 は 0 番目にあった seen[7] = 1 print(7 in seen) # True print(seen[7]) # 1

これで、配列を 1 周するあいだに答えが出ます。1 件あたりにやることは、引き算が 1 回、控えの確認が 1 回、控えへの記録が 1 回。どれも一定の時間なので、全体で O(n) です。1 万件なら 5000 万回が 1 万回になります。

その代わり、控えのぶんだけメモリを使います。最悪で全件ぶんです。時間を買うために場所を払っている、という取引になっています。

なお、控えを確認するのと記録するのは、順番を間違えると同じ位置の要素を 2 回使ってしまいます。目標がちょうど手元の値の 2 倍になる場合に何が起きるか、紙の上で 1 度たどってみてください。

要件

  1. 戻り値は [i, j] の 2 要素配列で、i < j を満たすこと
  2. map / HashMap / dict を使い、1 パスの O(n) で解く
  3. 同じインデックスを 2 度使ってはいけない (i != j)

入出力例

twoSum([2,7,11,15], 9) → [0,1] twoSum([3,2,4], 6) → [1,2] twoSum([3,3], 6) → [0,1] twoSum([-1,-2,-3,-4], -7) → [2,3] twoSum([1,5,3,8,2], 10) → [3,4] twoSum([0,4,3,0], 0) → [0,3]

ヒント

現在の要素 v に対して『相方 = target - v』を計算し、既に map に登録されていればその場で解

map への登録 (seen[v] = i) は if の後に行う。先に登録すると自分自身を相方にしてしまう罠

map のキーは値、バリューはインデックス。逆にすると相方検索ができない

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

関連レッスン

  • アナグラム判定

    2 つの文字列が同じ文字の並び替えになっているか (アナグラム) を、map による文字数カウントで判定する。

  • 第 4 章クイズ — データ構造 (基本)

    スタック / キュー / set / map の基本性質と計算量を 4 択で総まとめする。

  • バイト → KB 変換

    1024 で割って KB に変換し、容量表示の基本を体得する

  • Base64 エンコード後の長さ計算

    バイト列を Base64 エンコードしたときの文字数を、入力長から数式で求める関数を作ります。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 配列サイズ固定の同型データの集まり
  • ループ繰り返し処理。矢印で戻すか専用記号で示す
  • メモリプログラムとデータを一時保持する高速領域
  • 戻り値呼び出し元への返答を表す点線矢印
  • Map<K,V>キーと値のペアを保持する辞書 + 標準実装
  • インデックスDB 検索を速くする索引
main.py
学習モード
エディタを読み込んでいます

メモ

二数の和 (map で O(n))

⌘S で保存