每日算法练习: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,否则会直接报错。

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

相关推荐
A~MasterYi2 小时前
深入理解 Microscaling (MX) 格式:从浮点基础到共享指数矩阵乘法
算法·矩阵
环黄金线HHJX.2 小时前
《Tuan(拼音字母)⇆团(Group)/&湍(Turbulence)/&双结构链路道/&文字、符号、语言/&源点设计、连接起:人类与自然+AICosmOS》
开发语言·人工智能·算法·编辑器
有时间要学习3 小时前
面试150——第七周
算法·面试·深度优先
AI科技星3 小时前
万能学习方法论的理论建构与多领域适配性研究(乖乖数学)
人工智能·学习·算法·机器学习·平面·数据挖掘
Ashore11_3 小时前
蓝桥杯16届Java研究生组
java·算法·蓝桥杯
6Hzlia3 小时前
【Hot 100 刷题计划】 LeetCode 76. 最小覆盖子串 | C++ 滑动窗口题解
c++·算法·leetcode
像素猎人3 小时前
蓝桥杯OJ2049蓝桥勇士【动态规划】【dp[n]不是符合题意的答案,只是以an结尾的子问题的答案】
c++·算法·蓝桥杯·动态规划·区间dp
羊小猪~~3 小时前
LLM--SFT简介
python·考研·算法·ai·大模型·llm·微调
广州灵眸科技有限公司3 小时前
瑞芯微(EASY EAI)RV1126B 人脸98关键点算法识别
开发语言·科技·嵌入式硬件·物联网·算法·php