← ブログ一覧

目標に最も近い2数の和 - 二点探索でO(n)に解く方法 - AlgoNote

ツーポインタソート2数の和コーディングテストAlgoNote

デュエットのパートナーをどう選ぶ?

歌の練習アプリ「ハーモニー」では、メンバーごとに音程スコアがあります。2人で歌うとき、2つのスコアの和が目標ハーモニー値Tに近いほど、デュエットがよく合います。

ところが、和がちょうどTになる2人がいないこともあります。だから目標は「和がTになるペア」ではなく、「和がTに最も近いペア」を見つけることです。

例: スコアが [12, 18, 25, 33, 41, 50]、目標が60なら? 答えは59 (18 + 41)。 差がわずか1で最も近いです。


最も単純な方法とその限界

まず思いつくのは、すべての2人の組み合わせを試すことです。和を求めて |和 - T| が最小のペアを覚えればよい。

問題は、メンバーがN人なら組み合わせが約N²/2個あること。Nが10万なら50億回 — 時間内に終わりません。O(n²)は遅すぎます。


核心アイデア: ソートを武器に(両端の二点探索)

ここに重要な前提があります。スコアが昇順にソート済みであることです。これを利用すれば、すべてのペアを見なくても答えが見つかります。

ポインタ2つを両端に置いて始めます。

  • left は最小値(左端)、right は最大値(右端)を指す
  • 2つの値の和を目標Tと比較します:

- 和 < T → 小さすぎる → より大きな値が必要 → left を右へ1つ

- 和 > T → 大きすぎる → より小さな値が必要 → right を左へ1つ

- 和 == T → 差0、これ以上近づけないので即答え

  • ペアごとに |和 - T| をこれまでの最良と比べ、より近ければbestを更新します。

これを leftright が出会うまで繰り返せば終わりです。


「なぜ片方だけ動かして安全なのか?」

最初は「片方のポインタだけ動かすと見逃すペアが出ないか?」と心配になります。でもソート済みだから安全です。

和がTより小さい場合を考えてみましょう。いま right は右端なので、可能な限り大きな値と組んでいます。それでも和が小さいなら、right を減らして作るペアは和がさらに小さくなるだけ — Tに近づくことは決してありません。だからそれらのペアは捨てて安全で、和を大きくする唯一の手段である left++ だけすればよいのです。

和がTより大きい場合も対称に同じ理屈が成り立ちます。だから各ポインタは一方向にだけ動き、全体がO(n)で終わります。


ひと目でわかる計算量

方法時間計算量備考
全ペア比較O(n²)単純だがNが大きいと不可
両端の二点探索O(n)ソート前提、各ポインタ一方向移動
(未ソートなら)O(n log n)先にソートしてから二点探索

よくあるミス

  • bestの初期化漏れ: 最初のペアをbestに入れておかないと比較の基準がありません。
  • 差を絶対値で比較しない: 必ず |和 - T| で比較し、上下どちらも公平に扱います。
  • ソート確認漏れ: 入力がソート済みと保証されないなら、先にソートします。
  • 終了条件の誤り: left < right の間だけ繰り返し、同じ人を2回選ばないようにします。

AlgoNoteで直接確認しましょう

2つのポインタが両端からどう絞り込むのか、そしてbestが更新される瞬間は、目で見てこそ確実に理解できます。和が目標より大きいとき・小さいときにポインタがどう反応するか、1ステップずつ追ってみてください。

目標に最も近い2数の和 - 段階的な可視化で解法を見る →

目標に最も近い2数の和 - 二点探索でO(n)に解く方法 - AlgoNote - AlgoNote | 알고노트(AlgoNote)