这道题目来自AcWing 800题,要求我们在两个升序排列的数组中找到一对元素,使它们的和等于给定的目标值x。具体来说:
这个问题看似简单,但考察了我们对双指针算法的理解和应用能力。双指针算法是算法竞赛和面试中的常客,掌握它能显著提升解题效率。
最直接的解法是暴力枚举所有可能的(i,j)组合:
cpp复制for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
if(a[i]+b[j] == x)
return {i,j};
这种方法的时间复杂度是O(n*m),当n和m较大时(比如1e5),这种解法显然会超时。
暴力法的主要问题在于没有利用数组已经有序这个重要条件。在有序数组中,我们通常可以通过一些优化手段来减少不必要的计算。
观察到两个数组都是升序排列的,我们可以利用这个性质设计更高效的算法:
为什么这个算法是正确的?关键在于数组的有序性:
这种单调性保证了我们不会错过正确的解。
cpp复制#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N], b[N];
int main() {
int n, m, x;
cin >> n >> m >> x;
// 读入a,b两个数组,注意它们两个都是升序的
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < m; i++) cin >> b[i];
for (int i = 0, j = m - 1; i < n; i++) {
while (j > 0 && a[i] + b[j] > x) j--;
if (a[i] + b[j] == x) cout << i << " " << j << endl;
}
return 0;
}
cpp复制for (int i = 0, j = m - 1; i < n; i++) {
while (j > 0 && a[i] + b[j] > x) j--;
if (a[i] + b[j] == x) cout << i << " " << j << endl;
}
这段代码实现了双指针算法:
原代码中的while条件可以优化:
cpp复制while (j >= 0 && a[i] + b[j] > x) j--;
这样更清晰地表达j可以减到0。
需要考虑的边界情况包括:
在实际编程竞赛中,即使题目有保证,养成处理边界情况的习惯也很重要。
双指针算法常见于以下场景:
掌握双指针算法的关键在于理解指针移动的条件和方向,这需要大量的练习和总结。
为了巩固双指针算法,建议练习以下题目:
在实际工程中,这种算法思想可以应用于:
理解算法的本质比记忆具体实现更重要,这样才能灵活应用到各种场景中。
对于两数之和问题,常见的解法有:
选择哪种算法取决于具体问题和约束条件。在本题中,双指针是最优解。
在实现双指针算法时,建议:
良好的编码习惯能减少错误,提高解题效率。