【LeetCode#第167题】两数之和Ⅱ

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

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

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

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

 
示例 1:

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

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

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

提示:

2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 非递减顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案

167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

算法设计

        拿到这道题,想到了很多方法?二分法?哈希表?但是他们都有自己的弊端,二分法必须套在二层循环里,哈希表必须使用桶式结构来保存哈希标签重合的Index,且代码逻辑比较复杂。

        想要以最快速度解决这道题,真正的入手点在数学。首先需要意识到一个点,我们是能通过不断求取局部最优解来获得全局最优解的,为什么这么说?

        求解规则:

        1. 定义头指针尾指针,并分别初始化在表头表尾。

        2. 如果头尾指针指向元素和等于target,则返回标签

        3. 如果头尾指针指向元素和大于target,尾指针--;

        4. 如果头尾指针指向元素和小于target,尾指针++;

        5. 跳到2直到head和tail重合或tail<head;

        为什么能如此自信的通过一步步贪心求得最终解?难道这个过程中不会遗漏掉最终解吗?

        我们正常推理不太好思考,不如用反证法

        假设上述求解规则中,两个最终标签解被称为小解和大解。会出现head大于小解或tail小于大解的情况:

        1. head大于小解,tail大于等于大解 =》则必然有一刻head等于小解,tail大于大解 =》此时头尾指向和必然大于target =》则tail左移即可得到结果,head没有机会右移 =》不存在head大于小解tail大于等于大解,与题设矛盾

        2. head小于等于小解,tail小于大解 =》某一刻有tail等于大解,head小于小解 =》头尾指向和小于target =》此时head右移即可求解,tail没有机会左移 =》不存在head小于等于小解,tail小于大解,与题设矛盾

        命题得证

代码实现

int* twoSum(int* numbers, int numbersSize, int target, int* returnSize) {
    int head=0,tail=numbersSize-1;
    int * ret=(int*) malloc(sizeof(int)*2);
    while(head<tail){
        if(*(numbers+head)+*(numbers+tail)==target){
            ret[0]=head+1;
            ret[1]=tail+1;
            *(returnSize)=2;
            return ret;
        }
        if(*(numbers+head)+*(numbers+tail)>target){
            tail--;
        }
        if(*(numbers+head)+*(numbers+tail)<target)
            head++;
        }
    *(returnSize)=0;
    return ret;
}

        

        

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值