16. 3Sum Closest

練習日期:2026-04-20

難度:Medium

類型:Array、Two Pointers、Sorting

📘 題目敘述

給定一個整數陣列 nums,以及一個整數 target

請找出三個索引互不相同的數,使它們的總和最接近 target

最後回傳這三個數的總和。

題目保證每組輸入都剛好有唯一答案。

條件限制

  • 3 <= nums.length <= 500
  • -1000 <= nums[i] <= 1000
  • -10^4 <= target <= 10^4

🧠 解題思路

我這題的想法和 3Sum 很像,先排序,再固定一個數,剩下兩個數用 two pointers 去找。

因為排序之後,如果目前三數總和太大,我就可以把右指標往左移;如果總和太小,我就把左指標往右移。 這樣可以在每個固定的 i 下,有效率地找出更接近 target 的三數總和。

我在過程中用 ans 記錄目前最接近 target 的答案。

每次算出新的三數總和 sum,就比較:

  • 目前答案和 target 的距離
  • 新總和和 target 的距離

如果新的比較近,就更新 ans

所有變數

  • ans:目前找到最接近 target 的三數總和
  • n:陣列長度
  • l:左指標
  • r:右指標
  • sum:目前這組三個數的總和

🪜 主要流程步驟

1. 先初始化答案,並把陣列排序

我先把答案 ans 設成前三個數的總和:

int ans = nums[0] + nums[1] + nums[2];

這樣後面在比較時,一定已經有一個合法初始答案可以參考。

接著我把整個陣列排序:

sort(nums.begin(), nums.end());

排序之後,才能利用 two pointers 的性質來調整總和大小。


2. 固定第一個數,剩下兩個數用 two pointers 尋找

我用外層迴圈固定第一個位置 i

for (int i = 0; i < n - 2; i++) {

因為總共要選三個數,所以 i 最多只需要跑到 n - 3

接著在每個 i 底下,我設:

  • l = i + 1
  • r = n - 1

也就是在 i 右邊那段區間裡,用左右指標去找另外兩個數。


3. 計算目前三數總和,必要時更新答案

l < r 的時候,我先算出目前這組三數總和:

int sum = nums[i] + nums[l] + nums[r];

然後比較它和 target 的距離,看看有沒有比目前的 ans 更接近:

if (abs(ans - target) > abs(sum - target)) {
    ans = sum;
}

如果新的 sum 更接近 target,我就把答案更新成 sum


4. 根據目前總和和 target 的關係移動指標

更新完答案後,我就看目前的 sumtarget 的大小關係。

如果:

if (sum > target) {
    r--;
}

表示現在總和太大了。 因為陣列已經排序好,所以我要讓總和變小,就把右指標左移。

否則:

else {
    l++;
}

表示目前總和小於等於 target。 這時要讓總和變大,就把左指標右移。

這樣每次都能朝著更接近 target 的方向繼續找。


5. 全部掃完後回傳最接近的總和

當所有 i 都處理完之後,ans 裡面記錄的就是整個陣列中最接近 target 的三數總和,直接回傳即可。

⏱️ 複雜度

n = nums.length

  • 時間複雜度:O(n^2) 排序是 O(n log n),外層固定一個數之後,內層 two pointers 總共是 O(n),所以整體是 O(n^2)
  • 空間複雜度:O(1) 如果不計排序所需的額外空間,這份寫法只用了固定數量的變數。

💻 程式碼實作

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int ans = nums[0] + nums[1] + nums[2];
        int n = nums.size();
        sort(nums.begin(), nums.end());
        for (int i = 0; i < n - 2; i++) {
            int l = i + 1, r = n - 1;
            while (l < r) {
                int sum = nums[i] + nums[l] + nums[r];
                if (abs(ans - target) > abs(sum - target)) {
                    ans = sum;
                }
                if (sum > target) {
                    r--;
                } else {
                    l++;
                }
            }
        }
        return ans;
    }
};

https://leetcode.com/problems/3sum-closest/

作者: scottnick
撰寫日期: 2026-04-20
類別:
原文連結: https://scottnick.github.io/cpp-notes/all%20problems/16-3sum-closest.html