LeetCode 167——Two Sum II - Input array is sorted

给定已排序的整数数组,找到两个数使它们的和等于特定目标值。返回1-based索引,确保index1 < index2。本文介绍了使用两指针法解决此问题的思路和证明过程。

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.

Note:

  • Your returned answers (both index1 and index2) are not zero-based.
  • You may assume that each input would have exactly one solution and you may not use the sameelement twice.

Example:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.

 


 

题意没有什么特别的,但是注意返回的时候索引的计数方式,是以1为起始点的。

 

这道题的暴力解法就是遍历数组并使用O(N)的额外空间为其建立一个哈希表,然后再次遍历数组计算当前值与目标值的差值,查看哈希表中是否有这个值。方法虽然简单,但是并不值得推荐。

 

暴力的解法一开始我没有直接去想,因为这道题是求两个数的和为一个指定的值,而恰巧数组又是按照升序排列的,那么很自然的就想到了"two pointer"

 那么这个思想到底能不能行得通呢?首先对这两个数字的寻找方向应该是从两边到中间的,并且依据当前的和值是大于目标值还是小于目标值来决定是左边的索引 +1 还是右边的索引 -1。

以上就是大致的思路,但是是否能找到对应的结果还需要进一步的证明:

因为题目中没有说明数组中的整数是否均为非负数,所以我们就应按照有负数处理。如下是一张数轴图,假设某种情况下的唯一解的索引对应的值为A和B,左侧索引对应的值为i,右侧索引对应的值为j。他们一共可能出现4种情况:

  1. i < A, j > B.
  2. i > A, j > B.
  3. i < A, j < B.
  4. i > A, j < B.

第一种情况为初始时的一般情况,而第二三种情况一定不会发生,以第二种情况为例:i的值大于左侧解的值,可是此时 i + j > A + B,一定成立,但是我们每次移动后就会对i和j的值进行求和,若已经大于目标值,此时应该对右侧索引的值 -1,也就是减小j的值,假设在到达这种情况之前的某一时刻 i = A,j > B,此时 i + j > A + B 已经成立,应该减小j的值,i的值不会再增大。使用反证法也就证明了这种情况不会成立。同理情况三也不会成立。

那么情况四会不会成立呢?答案是不会,若不经过第一种情况,那么一定是先达到了第二、三种状态,但是上边我们已经证明二三种状态一定不会发生,那么情况四也一定不会发生。可知逐渐逼近的方法是可行的。

 

这道题总结下来就是:思路来自算法和经验,而证实则使用了简单的数学公式和反证法。数学的精妙和伟大不言而喻。

 


 

AC代码:

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] indices = new int[2];
        if (numbers == null || numbers.length < 2) {
            return indices;
        }
        
        int left = 0, right = numbers.length - 1;
        while(left < right) {
            int sum = numbers[left] + numbers[right];
            if (sum == target) {
                indices[0] = left + 1;
                indices[1] = right + 1;
                break;
            } else if (sum > target) {
                --right;
            } else {
                ++left;
            }
        }
        
        return indices;
    }
}

 


如有错误,欢迎指摘。欢迎通过左上角的“向TA提问”按钮问我问题,我将竭力解答你的疑惑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值