問題
整数のnums と、target をnums からtarget に
- 「近い」は、
和と targetの差の 大きさ (大きい ほうから 小さい ほうを 引いた 値) が 小さい ことです。 和が targetとちょうど 同じなら、 それが答えです - いちばん近い和は 1 つに
決まる ものとします。 たとえば targetが 5 で、和 4 と 和 6 が どちらも 作れて、 それより 近い 和が 無い、という 入力は 渡しません - 同じ
値が 何度出てきてもかまいません。 位置が 違えば 別の 数として使えます numsの長さは 3 以上 500 以下、 値は どれも 絶対値が 1000 以下、 targetは絶対値が 10000 以下です
入力と出力の例
例 1
-1、4、7 を
入力
nums = [4, -1, 7, 2, -5]
target = 11出力
10例 2
どのtarget より
入力
nums = [1, 1, 1, 0]
target = -5出力
2例 3
-8、3、5 で
入力
nums = [-8, 3, 5, 10, 6]
target = 0出力
0面接での聞かれ方
面接では、
- 「ちょうど
同じ 和が 無い ときは、 いちばん近い和を 返してください」と、 条件を 変えて 聞かれます - 「全部の
組を 試すと、 長さ 500 で どれくらい 時間が かかりますか?」と、 素直な 書き方の 重さを 聞かれます - 書き終えた
あとに 「並べ替えた 理由は 何ですか?」 「指を 動かして、 答えを 飛ばさないと 言えますか?」と、 考えの 筋を 聞かれます
ちょうどの
アルゴリズムのチートシートの「配列と文字列」に、この型の要点を表とコードでまとめています。
まず 考える手順
段 1
まずはtarget との
段 2
並びを
段 3
左のtarget にtarget より
段 4
候補の
解答
Python
Python
def three_sum_closest(
nums, target
):
a = sorted(nums)
n = len(a)
best = a[0] + a[1] + a[2]
gap = abs(best - target)
for i in range(n - 2):
x = a[i]
j = i + 1
k = n - 1
while j < k:
s = x + a[j] + a[k]
if s == target:
return s
d = abs(s - target)
if d < gap:
best = s
gap = d
if s < target:
j += 1
else:
k -= 1
return bestJavaScript
JavaScript
function threeSumClosest(
nums, target
) {
const a = [...nums].sort(
(p, q) => p - q
);
const n = a.length;
let best = a[0] + a[1] + a[2];
let gap = Math.abs(
best - target
);
const m = n - 2;
for (let i = 0; i < m; i++) {
const x = a[i];
let j = i + 1;
let k = n - 1;
while (j < k) {
const s = x + a[j] + a[k];
if (s === target) {
return s;
}
const d = Math.abs(
s - target
);
if (d < gap) {
best = s;
gap = d;
}
if (s < target) {
j++;
} else {
k--;
}
}
}
return best;
}Go
Go
import "sort"
func threeSumClosest(
nums []int, target int,
) int {
a := append([]int{}, nums...)
sort.Ints(a)
n := len(a)
best := a[0] + a[1] + a[2]
gap := absInt(best - target)
for i := 0; i+2 < n; i++ {
x := a[i]
j, k := i+1, n-1
for j < k {
s := x + a[j] + a[k]
if s == target {
return s
}
d := absInt(s - target)
if d < gap {
best, gap = s, d
}
if s < target {
j++
} else {
k--
}
}
}
return best
}
func absInt(x int) int {
if x < 0 {
return -x
}
return x
}受け取った nums はsort には、(p, q) => p - q を
計算量
- 時間は O(n²) です。
並べ替えに O(n log n)、 その あと 左の 数を 決める たびに、 2 本の 指が 出会 うまで O(n) 進み、 それを n 回くり返します - 使う
記憶は O(n) です。 並べ替えた 写しの 分です。 受け取った 並びを そのまま 並べ替えて よいなら、 指と 候補の 置き場だけで済みます - 素直な 3 重の
繰り返しの O(n³) から、 並べ替えと 両端の 指で 一段縮めました
よく ある間違い
- 候補を 0 や 0 に
近い数で始める。 どの 組でも 作れない 値が 答えとして 残る ことがあります。 最初の 候補は、 実際に ある 3 つの 和にします - 差の
大きさではなく、 差その ものを比べる。 和が targetより小さいと 差は 負の 数に なり、 遠い ほど 「小さい」と 見てしまいます。 比べる 前に 絶対値を取ります - JavaScript で
比べる 関数を 渡さずに sortする。 何も渡さないと 文字として 並べるので、 [-5, -1, 2]が[-1, -5, 2]になり、 指の 寄せ方が 成り立たなくなります
解答を動かした版 Python 3.12.14Node.js 22.23.4Go 1.24.6確認日 2026年10月30日
面接での 話し方の例
書き始める
「全部の
組を 試すと O(n³) です。 並べ替えてから、 いちばん左の 数を 1 つ 決め、 残りの 2 つは 両端の 指で 寄せます。 和が 小さければ 左を 進め、 大きければ 右を 戻し、 見た 和を 全部 候補と 比べます。 ちょうど 同じなら すぐ 返します。 時間は O(n²)、 記憶は 並べ替えた 写しの O(n) です。」
書き終えたら、
「例 1 は
並べ替えると [-5, -1, 2, 4, 7]です。-5を決めると、 -1と7で 1、2と7で 4、4と7で 6 と、どれも 11 より 小さいので 左を 進めます。 -1を決めると、 2と7で 8、4と7で 10 になり、 差が 1 の 10 が 候補に なります。 2を決めると 4と7で 13 で、差は 2 なので 入れ替えません。 答えは 10 です。」
