题目描述

✅ LCR 006. 两数之和 II - 输入有序数组

image-20260928234709661

image-20260928234709662

题意分析

在已经非递减排序的数组 numbers 中,找到两个不同位置,使对应元素之和等于 target,返回这两个位置的下标。题目保证恰好有一个有效答案。

本题下标从零开始,结果满足前一个下标小于后一个下标;这与主站第 167 题的一基下标不同。相同数值可以出现在不同位置,但不能重复使用同一位置,也不需要再次排序。

解法:有序数组两端双指针

核心思路

[!blue]

用 left、right 指向当前候选区间的两端,先比较这两个数的和。排序保证左端是当前最小候选,右端是当前最大候选,所以每次比较都能排除一个不可能参与答案的端点。

若和小于目标,左端即使配上当前最大的右端也不够,改配区间内更小的数只会更小,因此可以排除当前左端,让 left 右移。若和大于目标,右端即使配上当前最小的左端也过大,配上更大的数更不可能满足,因此让 right 左移。

已排除的端点都不可能与剩余候选形成答案,所以唯一答案始终留在尚未排除的区间中。两指针严格保持不同位置;和等于目标时,直接返回当前零基下标即可。

每轮至少移走一个端点,候选区间持续缩小,不需要额外哈希表。代码保留宽整数求和,且整个过程中不修改输入数组或下标对应关系。

解题步骤

  1. 初始化 left = 0、right = numbers.length - 1。
  2. 在 left < right 时计算两端和。
  3. 和等于目标则返回两个当前下标;偏小就右移左端,偏大就左移右端。
  4. 题目保证有解,合法输入会在两指针相遇前找到答案。

代码实现

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int left = 0;
        int right = numbers.length - 1;

        while (left < right) {
            long sum = (long) numbers[left] + numbers[right];

            if (sum == target) {
                return new int[] {
                    left,
                    right
                };
            }

            if (sum < target) {
                left++;
            } else {
                right--;
            }
        }

        return new int[0];
    }
}
func twoSum(numbers []int, target int) []int {
    left, right := 0, len(numbers)-1
    for left < right {
        sum := int64(numbers[left]) + int64(numbers[right])
        if sum == int64(target) {
            return []int{
                left,
                right,
            }
        }
        if sum < int64(target) {
            left++
        } else {
            right--
        }
    }
    return []int{}
}

复杂度分析

设数组长度为 $n$。

  • 时间复杂度:$O(n)$,两个指针合计最多移动线性次数。
  • 辅助空间复杂度:$O(1)$,只使用端点和求和变量,返回结果长度固定为二。

关键点总结

[!green]

  • 移动端点基于“与剩余最有利对手仍无法满足”的排除论证。
  • 输入有序,因此能同时维持候选区间和原始位置对应关系。
  • 返回零基下标,并用 left < right 保证不同位置。

易错点总结

[!yellow]

  • 本题下标不用加一,不能直接复制主站第 167 题的返回格式。
  • 和偏小时应增大左侧候选,偏大时应减小右侧候选,移动方向不能颠倒。
  • 两指针相同会复用一个元素,循环不能使用 left <= right。
  • 重复数值并不代表重复位置,不能先去重。
  • 数组已经有序,不必重新排序或额外改变原下标。

相似题目

题目 难度 关联与区别
1. 两数之和 简单 原题无序,需要哈希查互补值;本题有序,可以用两端指针线性收缩。
15. 三数之和 中等 先固定一个值后,剩余部分同样转化为有序两数之和,并增加结果去重。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2026/15885564
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!