【leetcode】—两数之和 II - 输入有序数组

image-20240928161226433

✏️ 关于专栏:专栏用于记录 LeetCode 中做题与总结
😭 补救 😭

两数之和 II - 输入有序数组

题目描述

题目链接:167. 两数之和 II - 输入有序数组

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

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

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

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

题目示例

示例 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
  • 仅存在一个有效答案

思路&代码

这道题与之前遇到的1. 两数之和的基础上测试用例的范围增大,且数组改为有序数组。那么之前的遍历枚举就会出现超时情况,利用哈希的还是可以用,但不推荐,毕竟这是一个有序数组

1.哈希表
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        unordered_map<int,int> mp;
        for(int i = 0;i < numbers.size();i++){
            auto it = mp.find(target - numbers[i]);
            if(it != mp.end()){
                return {it->second+1,i+1};
            }
            mp[numbers[i]] = i;
        }
        return {};
    }
};

需要注意的是这里题目要求下标从1开始,所以返回时候需要加1,具体的思路可以查看https://blog.csdn.net/m0_74014989/article/details/142617788?fromshare=blogdetail&sharetype=blogdetail&sharerId=142617788&sharerefer=PC&sharesource=m0_74014989&sharefrom=from_link

2.双指针

首先我们先来清楚一下什么是双指针。

双指针(Two Pointers):指的是在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的。如果两个指针方向相反,则称为「对撞指针」。如果两个指针方向相同,则称为「快慢指针」。如果两个指针分别属于不同的数组 / 链表,则称为「分离双指针」。

解题思路:我们定义left = 0,right = numbers.size() - 1两个指针,即分别指向numbers数组的左右两边,每次计算两个指针指向的两个元素之和,并和目标值比较。如果两个元素之和等于目标值,则发现了唯一解。如果两个元素之和小于目标值,则将左侧指针右移一位。如果两个元素之和大于目标值,则将右侧指针左移一位。移动指针之后,重复上述操作,直到找到答案。

image-20240929123912109
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left = 0,right = numbers.size() - 1;
        while(left < right){
            if(numbers[left] + numbers[right] == target){
                return {left+1,right+1};
            }else if(numbers[left] + numbers[right] < target){
                left++;
            }else{
                right--;
            }
        }
        return {};
    }
};
3.二分查找

首先固定第一个数,然后寻找第二个数,第二个数等于目标值减去第一个数的差。利用数组的有序性质,可以通过二分查找的方法寻找第二个数。为了避免重复寻找,在寻找第二个数时,只在第一个数的右侧寻找。

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

知识整理

双指针简介

双指针(Two Pointers):指的是在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的。如果两个指针方向相反,则称为「对撞指针」。如果两个指针方向相同,则称为「快慢指针」。如果两个指针分别属于不同的数组 / 链表,则称为「分离双指针」。

在数组的区间问题上,暴力算法的时间复杂度往往是 O ( n 2 ) O(n^2) O(n2)。而双指针利用了区间「单调性」的性质,可以将时间复杂度降$ O(n)$。

对撞指针

对撞指针:指的是两个指针 l e f t left left r i g h t right right分别指向序列第一个元素和最后一个元素,然后 l e f t left left指针不断递增, r i g h t right right 不断递减,直到两个指针的值相撞(即 l e f t = = r i g h t left == right left==right​),或者满足其他要求的特殊条件为止。

对撞指针

对撞指针求解步骤
  1. 使用两个指针 l e f t left left r i g h t right right l e f t left left指向序列第一个元素,即:$left = 0 , , right 指向序列最后一个元素,即: 指向序列最后一个元素,即: 指向序列最后一个元素,即:right = len(nums)−1$。
  2. 在循环体中将左右指针相向移动,当满足一定条件时,将左指针右移, l e f t + = 1 left += 1 left+=1。当满足另外一定条件时,将右指针左移,$right -= 1。
  3. 直到两指针相撞(即 l e f t = = r i g h t left == right left==right​​),或者满足其他要求的特殊条件时,跳出循环体。
对撞指针伪代码模板
int left = 0,right = nums.size() - 1;
while left < right:
    if 满足要求的特殊条件:
        return 符合条件的值 
    else if 一定条件 1:
        left += 1
    else if 一定条件 2:
        right -= 1

return 没找到 或 找到对应值
对撞指针适用范围

对撞指针一般用来解决有序数组或者字符串问题:

  • 查找有序数组中满足某些约束条件的一组元素问题:比如二分查找、数字之和等问题。
  • 字符串反转问题:反转字符串、回文数、颠倒二进制等问题。
对撞指针适用范围

对撞指针一般用来解决有序数组或者字符串问题:

  • 查找有序数组中满足某些约束条件的一组元素问题:比如二分查找、数字之和等问题。
  • 字符串反转问题:反转字符串、回文数、颠倒二进制等问题。
参考资料

https://github.com/itcharge/LeetCode-Py
d1fded34d21c16a44c687a112865ab0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值