每日算法练习:LeetCode 167. 两数之和 II - 输入有序数组 ✅

大家好,我是你们的算法小伙伴。今天我们来练习一道双指针的经典高频题 ------LeetCode 167. 两数之和 II - 输入有序数组。这道题是「两数之和」的进阶版本,利用数组有序的特性可以实现时间和空间的双重优化,是面试中考察双指针思想的标杆题目。


题目描述

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1]numbers[index2] ,则 1 <= index1 < index2 <= numbers.length

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1index2

你可以假设每个输入只对应唯一的答案 ,而且你不可以重复使用相同的元素

你所设计的解决方案必须只使用常量级的额外空间


示例 1:

复制代码
输入:numbers = [2,7,11,15], target = 9

输出:[1,2]

解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

示例 2:

复制代码
输入:numbers = [2,3,4], target = 6

输出:[1,3]

解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

示例 3:

复制代码
输入:numbers = [-1,0], target = -1

输出:[1,2]

解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

提示:

  • 2 <= numbers.length <= 3 * 10^4
  • -1000 <= numbers[i] <= 1000
  • numbers非递减顺序 排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案

解题思路

核心特性拆解

数组的核心特性:非递减有序 + 唯一答案 + 常量空间限制

  • 无序数组的两数之和用哈希表(时间 O (n),空间 O (n)),但本题要求常量空间,且数组有序,因此可以用双指针实现 O (1) 空间。
  • 双指针的核心逻辑:
    1. 左指针 left 指向数组开头(最小元素),右指针 right 指向数组末尾(最大元素);
    2. 计算两数之和 sum = numbers[left] + numbers[right]
      • sum == target:找到答案,返回 [left+1, right+1](题目下标从 1 开始);
      • sum < target:和太小,需要增大和,因此左指针右移(left++);
      • sum > target:和太大,需要减小和,因此右指针左移(right--);
    3. 由于数组有序,指针移动的方向唯一,不会错过正确答案,且保证时间复杂度 O (n)。

方法一:双指针法(最优解,符合空间要求)

思路:利用数组有序的特性,双指针从两端向中间遍历,一次遍历即可找到答案,空间复杂度 O (1),完美满足题目要求。

方法二:二分查找法(补充思路)

思路:遍历数组中的每个元素 numbers[i],计算目标补数 complement = target - numbers[i],然后在 i 之后的数组中用二分查找补数。时间复杂度 O (n log n),空间复杂度 O (1),但效率低于双指针法。


代码实现

方法一:双指针法(最优解)

复制代码
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int left = 0;
        int right = numbers.length - 1;
        
        while (left < right) {
            int sum = numbers[left] + numbers[right];
            if (sum == target) {
                // 题目下标从1开始,因此+1
                return new int[]{left + 1, right + 1};
            } else if (sum < target) {
                // 和太小,左指针右移
                left++;
            } else {
                // 和太大,右指针左移
                right--;
            }
        }
        // 题目保证有唯一答案,因此不会走到这里
        return new int[]{-1, -1};
    }
}

方法二:二分查找法(补充)

复制代码
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int n = numbers.length;
        for (int i = 0; i < n; i++) {
            int complement = target - numbers[i];
            // 在i之后的区间二分查找补数
            int left = i + 1, right = n - 1;
            while (left <= right) {
                int mid = left + (right - left) / 2;
                if (numbers[mid] == complement) {
                    return new int[]{i + 1, mid + 1};
                } else if (numbers[mid] < complement) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return new int[]{-1, -1};
    }
}

代码详解

一、双指针法

  1. 指针初始化left = 0(数组开头),right = numbers.length - 1(数组末尾)。
  2. 遍历逻辑
    • 每次计算两数之和,根据和与目标的大小关系移动指针;
    • 数组非递减的特性保证了:左指针右移只会增大和,右指针左移只会减小和,因此不会错过正确答案;
  3. 下标处理:题目要求下标从 1 开始,因此返回时给两个指针都 + 1。

示例 1 模拟numbers = [2,7,11,15], target = 9

  • left=0, right=3sum=2+15=17 > 9right=2
  • left=0, right=2sum=2+11=13 > 9right=1
  • left=0, right=1sum=2+7=9 == 9 → 返回 [1,2]

二、二分查找法

  1. 遍历每个元素 :以 numbers[i] 为第一个数,计算需要的补数 complement = target - numbers[i]
  2. 二分查找补数 :在 i+1 到末尾的区间内二分查找补数,找到则返回下标;
  3. 优缺点:空间复杂度同样 O (1),但时间复杂度 O (n log n),不如双指针法高效,仅作为补充思路。

复杂度分析

解法 时间复杂度 空间复杂度 优点 缺点
双指针法 O(n) O(1) 时间最优,空间最优,完全符合题目要求
二分查找法 O(n log n) O(1) 空间符合要求 时间效率低于双指针法

总结

  1. 核心考点 :本题的核心是利用数组有序的特性,用双指针将时间复杂度从哈希表的 O (n)(空间 O (n))优化为 O (n)(空间 O (1)),完美满足题目常量空间的要求。
  2. 面试优先级:双指针法是本题的最优解,面试中必须优先写出,代码简洁、逻辑清晰,几乎零出错。
  3. 拓展对比 :和「两数之和」(无序数组)的区别:
    • 无序数组:只能用哈希表(时间 O (n),空间 O (n));
    • 有序数组:双指针法(时间 O (n),空间 O (1)),是更优的解法。
  4. 易错点:题目下标从 1 开始,返回时必须给指针 + 1,否则会直接报错。

今天的每日算法练习就到这里,我们明天再见!👋

相关推荐
Robot_Nav19 分钟前
TD3 —— 双延迟深度确定性策略梯度算法文献解读
算法·td3·drl
斯维赤20 分钟前
每天学习一个小算法:归并排序
学习·算法·排序算法
王老师青少年编程25 分钟前
csp信奥赛C++高频考点专项训练之贪心算法 --【区间贪心】:区间覆盖(加强版)
c++·算法·贪心·csp·信奥赛·区间贪心·区间覆盖(加强版)
碧海银沙音频科技研究院32 分钟前
杰理项目开发大全课程
人工智能·深度学习·算法
风一样的航哥1 小时前
LeetCode 2615 等值距离和:前缀和优化O(n)解法深度解析
数据结构·算法·leetcode
生成论实验室1 小时前
生成态势猜想:一种统一的宇宙动力学语法
人工智能·科技·神经网络·算法·信息与通信
旖-旎2 小时前
深搜(二叉树的所有路径)(6)
c++·算法·leetcode·深度优先·递归
啦啦啦_99992 小时前
3. KNN算法之 常用的距离度量方式(欧式&曼哈顿&切比雪夫&闵式距离)
算法
朝风工作室2 小时前
实时全景拼接|支持任意路数输入,8*8K RTX3050 实测 10ms 内
图像处理·算法·计算机视觉
nianniannnn3 小时前
HNU计算机系统期中题库详解(五)位运算与逻辑运算
算法·位运算·计算机系统