快轉到主要內容

CSES-1641 Sum of Three Values

標籤: 雙指標
目錄


題目連結:https://cses.fi/problemset/task/1641

題意
#

題目給定一個長度為 \( n \) 的整數陣列,以及目標總和 \( x \)。
需要在陣列中找出「三個不同位置」的數字,使得相加總和等於 \( x \)。
若找到,輸出這三個數字在原始陣列中的索引位置;若無解,則輸出 IMPOSSIBLE

思路
#

此為經典的「3Sum」問題。
若使用三重迴圈窮舉,時間複雜度為 \(\mathcal{O}(N^3)\),會導致 TLE。
為了降低複雜度,可結合「排序」與「雙指標(Two Pointers)」。

首先,將數字與原始索引打包(例如使用 pair),並依照數字從小到大排序以保留輸出所需的原始位置。

尋找三個數字的策略為:「固定一個數字,尋找另外兩個」。
利用迴圈遍歷陣列,固定數字 v[i]
接著目標轉化為:在它「右側」的數字中,尋找兩個相加等於 x - v[i] 的數字。

這將問題轉換為雙指標應用場景:
設定左指標 li 的下一個位置,右指標 r 於陣列的最末端,向中間靠攏:

  • 若總和 sum 小於目標,代表需較大的數,將左指標 l 往右移。
  • 若總和 sum 大於目標,代表需較小的數,將右指標 r 往左移。
  • 若恰好 sum == x,即找到配對,提取原始索引並結束迴圈。

整體時間複雜度為 \(\mathcal{O}(N^2)\)。

程式碼
#

#include <bits/stdc++.h>
using namespace std;

#define pb push_back
#define fi first
#define se second
#define INF LONG_LONG_MAX/1000
#define WA() cin.tie(0)->sync_with_stdio(0)
#define all(x) (x).begin(), (x).end()
#define int long long
#define PII pair<int, int>

signed main() { WA();
    int n, x; cin >> n >> x;
    vector<PII> v(n);
    for (auto &i : v) cin >> i.fi, i.se = &i-v.data()+1;
    sort(all(v));
    int a, b, c; a = -1;
    for (int i = 0; i < n; i++) {
        for (int l = i+1, r = n-1; l < r;) {
            int sum = v[l].fi + v[r].fi + v[i].fi;
            if (sum < x) l++;
            else if (sum > x) r--;
            else {
                a = v[i].se, b = v[l].se, c = v[r].se;
                break;
            }
        }
    }
    if (~a) cout << a << ' ' << b << ' ' << c;
    else cout << "IMPOSSIBLE";
}
Piau 的筆記本
作者
Piau 的筆記本
希望我寫下來的東西能夠長久的記在我的腦中