题目描述:
给定一个已按照升序排列的整数数组nums,请从数组中找出满足两个数相加之和等于目标值target。
函数应该以长度为2*的整数数组的形式返回两个数的下标值。
每个输入只对应唯一的答案,而且不可以重复使用相同的元素。
示例 1:
输入: nums = [2, 9, 11, 13], target = 13
输出: [1, 2]
解释: 2 和 11之和等于目标数 13。 因此index1 = 1,index2 = 2。
示例 2:
输入: nums = [6, 9, 12], target = 18
输出: [1, 3]
解释: 6 和 12之和等于目标数 18。 因此index1 = 1,index2 = 3。
示例 3:
输入: nums = [-2, 0], target = -2
输出: [1, 2]
解释: -2 和 0之和等于目标数 -2。 因此index1 = 1,index2 = 2。
方法一:binarySearch
在数组中找到两个数,使得两元素之和sum等于目标值target,可以首先固定第一个元素,然后通过二分查找第二个元素:利用数组的升序排列的性质,第二个元素等于目标值减去第一个元素的值。为了避免重复查找,只在第一个元素的右侧查找第二个元素。 时间复杂度:O(nlogn),空间复杂度:O(1)。
\\二分查找算法
public int[] twoSum(int[] nums, int target) {
//判断数组是否为空
if (nums == null || nums.length == 0) return new int[0];
for (int i = 0; i < nums.length; i++) {
int x = nums[i];
// 线性查找 - O(n)
// 1. 二分查找 - O(logn)
// [i + 1, nums.length - 1] 区间二分查找 target - x
int index = binarySearch(nums, target - x);
if (index != -1) {
return new int[]{
i + 1, index + 1};
}
}
return new int[0];
}
二分查找算法
public int binarySearch(int[] nums, int target) {
int low = 0, high = nums.length - 1;//low、high分别表示为数组左侧低阶和数组右侧高阶的下标
while (low <= high) {
int mid = low + (high - 1)/2;//将数组从中间二分
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
//如果中间元素<目标值,则继续[mid+1, high]二分循环查找
low = mid + 1;
}
else {
//如果中间元素>目标值,则继续[low, mid-1]二分循环查找
high = mid - 1;
}
}
return -1;//在这个函数中,如果有异常就返回-1,即 return -1;
//这是一种编程技巧,如果出现异常就通过返回-1就知道该函数出现异常
}
方法二:doublePointer
利用数组的升序排列的性质,所以只需要使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。即. 指向较小的元素是从数组最开始从头向尾遍历,指向较大的元素是从数组最后面从尾往前遍历。
- 如果两个指针指向元素的之和 sum == target,那么得到要求的结果;
- 如果sum > target,移动较大的元素,使 sum 值变小;
- 如果sum < target,移动较小的元素,使 sum 值变大。
数组中的元素最多遍历一次,于是. 时间复杂度为O(N)。只使用两个额外的变量,空间复杂度为O(1)。
\\双指针算法
public int[] doublePointer(int[] nums, int target) {
//判断数组是否为空
if (nums == null || nums.length == 0) return new int[0];
int left = 0; //初始化数组开始位置的下标(左指针)
int right = nums.length - 1;//初始化数组结束位置的下标(右指针)
while (left < right) {
//如果左指针出现在右指针右侧,结束循环
int sum = nums[left] + nums[right];//求出左右指针位置值得和
//比较目标值target与两指针之和的大小
if (sum == target) {
return new int[] {
left + 1, right + 1};
} else if (sum < target) {
//两数之和小了,说面左指针处的值过小,左指针右移一位
left++;
} else {
//两数之和大了,说面右指针处的值过大,右指针左移一位
right--;
}
}
return new int[0];
}