题解:AcWing 800 数组元素的目标和

【题目来源】

AcWing:800 数组元素的目标和 - AcWing题库

【题目描述】

给定两个升序排序的有序数组 \(A\)\(B\),以及一个目标值 \(x\)

数组下标从 \(0\) 开始。

请你求出满足 \(A[i]+B[j]=x\) 的数对 \((i,j)\)

数据保证有唯一解。

【输入】

第一行包含三个整数 \(n,m,x\),分别表示 \(A\) 的长度,\(B\) 的长度以及目标值 \(x\)

第二行包含 \(n\) 个整数,表示数组 \(A\)

第三行包含 \(m\) 个整数,表示数组 \(B\)

【输出】

共一行,包含两个整数 \(i\)\(j\)

【输入样例】

4 5 6
1 2 4 7
3 4 6 8 9

【输出样例】

1 1

【核心思想】

  1. 问题分析:给定两个已按升序排列的数组 \(A\)(长度 \(n\))和 \(B\)(长度 \(m\)),以及目标和 \(x\),需要找到满足 \(A[i] + B[j] = x\) 的唯一数对 \((i, j)\)。这是一个双指针(对撞指针)问题,关键在于如何利用数组的有序性高效查找。

  2. 算法选择

    • 双指针(对撞指针):一个指针 \(i\) 从数组 \(A\) 的起始位置(\(0\))向右移动,另一个指针 \(j\) 从数组 \(B\) 的末尾位置(\(m-1\))向左移动
    • 单调性利用:由于 \(A\) 升序、\(B\) 升序,当 \(A[i]\) 增大时,需要 \(B[j]\) 减小才能保持和为 \(x\)
  3. 关键步骤

    • 初始化\(i = 0\)(指向 \(A\) 的起始),\(j = m - 1\)(指向 \(B\) 的末尾)
    • 遍历数组 \(A\)\(i\)\(0\)\(n-1\)):
      • 调整指针 \(j\):当 a[i] + b[j] > x 时,说明 \(B[j]\) 太大,需要 \(j\) 左移寻找更小的 \(B[j]\)
      • 检查条件:如果 a[i] + b[j] == x,找到答案,输出 \((i, j)\) 并结束
    • 由于数据保证有唯一解,一定能找到答案
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + m)\)\(i\) 最多遍历 \(n\) 次,\(j\) 最多左移 \(m\)
    • 空间复杂度:\(O(1)\),只使用了两个指针
  5. 双指针(对撞指针)的核心思想

    • 单调性利用:数组 \(A\) 递增、数组 \(B\) 递增,当 \(A[i]\) 增大时,\(B[j]\) 必须减小才能使和保持为 \(x\)
    • 对撞策略:一个指针从头开始,一个从尾开始,相向而行
    • 避免枚举:不需要枚举所有 \(n \times m\) 个数对,利用单调性将复杂度从 \(O(nm)\) 降到 \(O(n+m)\)
    • 贪心正确性:对于当前的 \(A[i]\),找到最大的 \(B[j]\) 使得 \(A[i] + B[j] \leq x\),如果等于则找到答案,如果小于则 \(i\) 右移(因为更大的 \(A[i]\) 需要更小的 \(B[j]\)
    • 适用于两数组之和等于目标值、两数之和类问题

【解题思路】

【算法标签】

双指针

【代码详解】

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

const int N = 100010;  // 定义数组最大长度

int n, m, x;          // n: 数组a的长度, m: 数组b的长度, x: 目标和
int a[N], b[N];       // 两个待处理的数组

int main()
{
    // 输入数组a的长度、数组b的长度和目标和x
    scanf("%d%d%d", &n, &m, &x);

    // 输入数组a的元素
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
    }

    // 输入数组b的元素
    for (int i = 0; i < m; i++)
    {
        scanf("%d", &b[i]);
    }

    // 双指针算法:i从数组a的起始位置开始,j从数组b的末尾开始
    for (int i = 0, j = m - 1; i < n; i++)
    {
        // 当两数之和大于x时,移动j指针向左寻找更小的数
        while (j >= 0 && a[i] + b[j] > x)
        {
            j--;
        }

        // 找到满足条件的数对
        if (a[i] + b[j] == x)
        {
            printf("%d %d\n", i, j);  // 输出下标
            break;                    // 找到后立即退出
        }
    }

    return 0;
}

【运行结果】

4 5 6
1 2 4 7
3 4 6 8 9
1 1
posted @ 2026-06-14 10:37  团爸讲算法  阅读(4)  评论(0)    收藏  举报