题目描述
给定一个大小为 n n n 的整数数组,你需要找到两个不同位置上的数,它们的和等于给定的目标值 x x x。
输入格式
第一行包含两个整数 n , x n, x n,x ------ 数组的大小和目标和。
第二行包含 n n n 个整数 a 1 , a 2 , ... , a n a_1, a_2, \dots, a_n a1,a2,...,an ------ 数组的元素。
输出格式
输出两个整数,表示这两个数的位置(下标从 1 开始)。
如果有多个解,可以输出任意一个。
如果没有解,输出 IMPOSSIBLE
。
样例输入
cpp
4 8
2 7 5 1
样例输出
cpp
2 4
数据范围
- 1 ≤ n ≤ 2 ⋅ 10 5 1 \le n \le 2 \cdot 10^5 1≤n≤2⋅105
- 1 ≤ x , a i ≤ 10 9 1 \le x, a_i \le 10^9 1≤x,ai≤109
提交链接
思路分析✨
朴素方法 🐢
最直接的想法是用两层循环,枚举所有数对:
- 外层循环遍历第一个数 a [ i ] a[i] a[i]
- 内层循环遍历第二个数 a [ j ] a[j] a[j]
- 判断是否满足 a [ i ] + a [ j ] = x a[i] + a[j] = x a[i]+a[j]=x
这样时间复杂度是 O ( n 2 ) O(n^2) O(n2)。
但本题 n n n 最大可达 2 ⋅ 10 5 2 \cdot 10^5 2⋅105,那么 O ( n 2 ) O(n^2) O(n2) 大约是 4 ⋅ 10 10 4 \cdot 10^{10} 4⋅1010 次操作,显然会超时 ⏰。
所以必须寻找 更高效的算法。⚡
更高效的思路 💡
我们希望能在 一次遍历 中解决问题。
观察公式: a [ i ] + a [ j ] = x ⟹ a [ j ] = x − a [ i ] a[i] + a[j] = x \implies a[j] = x - a[i] a[i]+a[j]=x⟹a[j]=x−a[i]
也就是说,在遍历数组时,对于每个元素 a [ i ] a[i] a[i],我们只需要知道 是否之前出现过某个数等于 x − a [ i ] x - a[i] x−a[i]。
如果出现过,那么这两个数就是答案 ✅。
数据结构的选择 🛠️
为了快速判断「某个数是否出现过」,我们需要:
- 哈希表
unordered_map
:平均复杂度 O ( 1 ) O(1) O(1) 🏎️ - 平衡二叉搜索树
map
:复杂度 O ( log n ) O(\log n) O(logn) 🐌
如下算法,选择 map<int,int>
来存储「值 → 位置」
的映射。
算法流程 📑
-
输入 n , x n, x n,x 和数组 a a a。
-
初始化一个映射 m m m,用于存储「已经出现过的数」及其位置。
-
遍历数组下标 i i i:
-
计算需要的补数: n e e d = x − a [ i ] need = x - a[i] need=x−a[i]
-
如果 m m m 中存在 n e e d need need,说明找到一对数: a [ i ] + n e e d = x a[i] + need = x a[i]+need=x
输出这两个数的位置 🎯。
-
否则,将当前数存入 m m m,继续遍历。
-
-
如果遍历结束仍未找到,输出
IMPOSSIBLE
。
时间复杂度与空间复杂度 ⏳
-
时间复杂度:
- 使用
map
时: O ( n log n ) O(n \log n) O(nlogn) - 使用
unordered_map
时:期望 O ( n ) O(n) O(n)
- 使用
-
空间复杂度 :
需要存储最多 n n n 个元素,复杂度为 O ( n ) O(n) O(n)。
总结 🎉
本题的关键在于利用「哈希 / 映射」来快速查找补数,从而将暴力解法的 O ( n 2 ) O(n^2) O(n2) 降到 O ( n log n ) O(n \log n) O(nlogn) 或 O ( n ) O(n) O(n)。 只需遍历数组一次即可找到答案,保证了在大数据范围内的可行性。✅
😎 一句话总结
"边走边记,随时看看我缺的另一半是不是已经来过了。" ❤️
参考代码
cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, x;
cin >> n >> x;
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
map<int, int> m;
for (int i = 1; i <= n; i++)
{
if(m.count(x - a[i]))
{
cout << i << " " << m[x - a[i]];
return 0;
}
m[a[i]] = i;
}
cout << "IMPOSSIBLE";
return 0;
}