167. 两数之和 II - 输入有序数组 - 力扣(LeetCode) (leetcode-cn.com)
难度:简单
题目描述:给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。
分析
* 此题和001最大的区别就是输入数组为非递减顺序排列的数组,即一个排序完成的数组。
* 本题有两种解题思路:
* 1- 二分查找,而二分查找最好查找一个数,对于此题来说,二分查找的时间复杂度为O(nlogn),空间复杂度为O(1),可以参考官方解题。
* 2- 双指针,本题最优解为双指针,时间复杂度为O(n),空间复杂度为O(1)。
* 双指针的一个思路为:
* 首先本题为非递减顺序排列的数组,可以知道数组中的值都是排序好的
* 即numbers[i]<=numbers[i+1]恒成立
* 本题需要找到两个数的和等于target
* 所以必然存在两个数 a + b = target && a <= b
* 想要找到a b ,只需要设置两个指针,一个指向数组头,一个指向数组尾
* 即i = 0, j = numbers.length - 1,
* 此时只需要分析numbers[i] + numbers[j] 与 targe的关系即可
* 举例:numbers = [1,2,3,7,9], target = 9
* 1- numbers[i] + numbers[j] > target
* 此时 i=0, j=4, numbers[0] + numbers[4] = 10 > 9
* 此时和数大于目标数,我们想降低和数,只能寻找小于numbers[0] 或者小于numbers[4]的数
* 显然寻找小于numbers[0]是不现实的,因为此数为最小数,所以只能寻找小于numbers[4]的数
* 即j--
* 2- numbers[i] + numbers[j] < target
* 此时 i=0, j=3, numbers[0] + numbers[3] = 8 < 9
* 和1- 同理,需要提高和数,只能寻找大于numbers[0] 或者大于numbers[3]的数
* 所以只能寻找大于numbers[0]的数
* 即i++
* 3- numbers[i] + numbers[j] = target
* 没什么好说的,这就是最终答案,而且题目说只对应唯一的答案,所以直接返回即可
* 一个小坑,
* 返回数组,需要将i,j加一,因为答案中起始是1,数组中起始是0
解题
class Solution {
public int[] twoSum(int[] numbers, int target) {
int i = 0, j = numbers.length - 1;
while (i<j){
if (numbers[i] + numbers[j] > target) {
j--;
} else if (numbers[i] + numbers[j] < target) {
i++;
} else {
return new int[]{i + 1,j + 1};
}
}
return new int[0];
}
}