题目描述

✅ 剑指 Offer 57. 和为s的两个数字

image-20261001230752586

题意分析

在递增排序的数组中选择两个不同位置,使对应数值之和等于 target。返回两个数值而非下标;有多组答案时,任意一组即可。

解法:双指针收缩边界

核心思路

[!blue]

用 left、right 指向尚未排除区间的两端,比较 nums[left] + nums[right] 与目标。数组有序,因此每次比较都能排除一个端点,而不只是排除当前这一对数。

若和偏小,左端与当前最大值相加都不够,改配区间内其他数只会更小,所以任何答案都不可能再使用这个左端,令 left++。若和偏大,右端与当前最小值相加都太大,改配其他数只会更大,所以可以令 right--。

已排除的端点都不可能参与剩余答案,合法数对始终留在两指针之间。和相等时直接返回;当两指针相遇,已没有两个不同位置可选,代码返回空数组。

解题步骤

  1. 初始化 left = 0、right = nums.length - 1。
  2. 当 left < right 时,计算两个端点的和 sum。
  3. sum == target 时返回两端数值;sum < target 时右移左指针,否则左移右指针。
  4. 循环结束仍未找到时返回空数组。

代码实现

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

        while (left < right) {
            int sum = nums[left] + nums[right];

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

            if (sum < target) {
                // 与当前最大值相加仍偏小,左端不可能属于答案。
                left++;
            } else {
                // 与当前最小值相加仍偏大,右端不可能属于答案。
                right--;
            }
        }

        return new int[0];
    }
}
func twoSum(nums []int, target int) []int {
    left, right := 0, len(nums)-1

    for left < right {
        sum := nums[left] + nums[right]
        if sum == target {
            return []int{
                nums[left],
                nums[right],
            }
        }
        if sum < target {
            // 与当前最大值相加仍偏小,左端不可能属于答案。
            left++
        } else {
            // 与当前最小值相加仍偏大,右端不可能属于答案。
            right--
        }
    }

    return []int{}
}

复杂度分析

  • 时间复杂度:$O(n)$,其中 n 为数组长度;每次循环使两指针的距离缩短 1,最多移动 n - 1 次。
  • 空间复杂度:$O(1)$,只使用两个指针和当前和。

关键点总结

[!green]

  • 有序性支持一次比较排除整个端点。
  • 相等数值可以来自不同位置,不能复用同一个下标。

易错点总结

[!yellow]

  • 和偏小时移动右指针,会使候选和更小并漏掉解。
  • 一次移动两端,没有分别排除两者的依据。
  • 返回指针下标而不是两数值,不符合本题要求。
  • 循环条件不能写成 left <= right,否则可能把同一个位置使用两次。

相似题目

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