两数之和算法 -- 输入有序数组

问题描述:

给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
注1:函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 < = a n s w e r [ 0 ] < a n s w e r [ 1 ] < = n u m b e r s . l e n g t h 1 <= answer[0] < answer[1] <= numbers.length 1<=answer[0]<answer[1]<=numbers.length
注2:你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]

示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]

示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]

思路分析与代码实现

方法一:二分法搜索

先固定第一个数,然后第二个数使用二分法来搜索。
代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
    int n = numbers.size();
        for (int i = 0; i < n; i++) {
			int low = i + 1;//第二个数保证在第一个数右边
			int high = n-1;
			while(low<=high) {
				int mid = low + (high - low) / 2;
				if(nums[i] = target - nums[mid])
					return {i+1,mid+1};
				else if (nums[i] < target - nums[mid]){
					low = mid + 1;
				}
				else
					high = mid - 1;
			}
		}
		return {-1,-1};//没有满足条件的目标
    }
};
  • 复杂度分析
    时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),其中 n n n 是数组的长度。需要遍历数组一次确定第一个数,时间复杂度是 O ( n ) O(n) O(n),寻找第二个数使用二分查找,时间复杂度是 O ( l o g n ) O(logn) O(logn),因此总时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn)
    空间复杂度: O ( 1 ) O(1) O(1)

方法二:双指针

由于原数组是有序数组(升序),并且只有唯一解,那么可以使用两个指针,分别指向第一个元素 i i i和最后一个元素 j j j。当两个元素 n u m b e r s [ i ] + n u m b e r s [ j ] numbers[i]+numbers[j] numbers[i]+numbers[j]小于目标值时,代表着 n u m b e r s [ i ] numbers[i] numbers[i]无法满足要求(太小),则 i + + i++ i++。如果当两个元素 n u m b e r s [ i ] + n u m b e r s [ j ] numbers[i]+numbers[j] numbers[i]+numbers[j]大于目标值时,代表着 n u m b e r s [ i ] numbers[i] numbers[i]无法满足要求(太大),则 j + + j++ j++。当两个元素 n u m b e r s [ i ] + n u m b e r s [ j ] numbers[i]+numbers[j] numbers[i]+numbers[j]等于目标值时,输出 i + 1 , j + 1 i+1,j+1 i+1,j+1
其代码如下:

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left= 0, right= numbers.size() - 1;
        while(left <= right) {
       		int mid = left + (right - left) / 2;
       		if (numbers[left] < target - numbers[right]) {
				left++;
			}
			else if(numbers[left] > target - numbers[right]) {
				right--;
			}
			else {
				return {left+1,right+1};
			}
        }
        return {-1,-1};
    }
};

  • 复杂度分析
    时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组的长度。两个指针移动的总次数最多为 n n n 次。
    空间复杂度: O ( 1 ) O(1) O(1)

随写:

该题目有几个特点:
1、数组有序,这给双指针很大便利;
2、双指针一般是固定一个,移动另一个;
3、二分法一般用于有序数列,折半查找。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值