LeetCode | 167 | 两数之和2-输入有序数组 | 二分法 | 双指针

二分查找你学废了吗?快来看看这道题如何使用二分查找解决吧!

LeetCode链接:167. 两数之和 II - 输入有序数组

1.题目描述

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

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

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

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

示例 1:

1
2
3
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2]

示例 2:

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

示例 3:

1
2
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
  • 仅存在一个有效答案

2.题解

  • 这道题目是1. 两数之和的变体,其解题方法均可以用在该方法上,但是并没有利用这道题目的特性:数组为 非递减顺序排列
  • 二分查找的时间复杂度$O(nlog(n))$
  • 双指针的时间复杂度$O(n)$

2.1 二分查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int[] twoSum(int[] numbers, int target) {
// 遍历数组
for (int i = 0; i < numbers.length; i++) {
// 计算新的目标值
int newTarget = target - numbers[i];
// 二分查找初始化
int left = i + 1, right = numbers.length - 1;
// 使用二分查找寻找新的目标值
while (left <= right) {
int mid = left + (right - left) / 2;
if (numbers[mid] == newTarget) {
// 找到目标值,返回结果
return new int[] { i + 1, mid + 1 }; // 索引从1开始
} else if (numbers[mid] < newTarget) {
// 中间值小于新目标值,向右移动左边界
left = mid + 1;
} else {
// 中间值大于新目标值,向左移动右边界
right = mid - 1;
}
}
}
// 未找到结果,返回 [-1, -1]
return new int[] { -1, -1 };
}
}

2.2 双指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int[] twoSum(int[] numbers, int target) {
// 初始化左右指针
int left = 0, right = numbers.length - 1;

// 使用双指针法寻找两个数的和等于目标值
while (left <= right) {
// 计算当前左右指针所指向元素的和
int sum = numbers[left] + numbers[right];

// 如果和大于目标值,右指针左移
if (sum > target) {
right--;
// 如果和小于目标值,左指针右移
} else if (sum < target) {
left++;
// 如果和等于目标值,返回结果
} else {
return new int[] { left + 1, right + 1 }; // 注意返回的索引从1开始
}
}

// 如果没有找到满足条件的两个数,返回 [-1, -1]
return new int[] { -1, -1 };
}
}
-------------本文结束感谢您的阅读-------------