双指针(6)_单调性_查找总价格为目标值的两个商品

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

双指针(6)_单调性_查找总价格为目标值的两个商品

收录于专栏【经典算法练习
本专栏旨在分享学习C++的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1. 题目链接:

2.题目描述 :

3.解法 :

    解法一(暴力枚举) :

    算法思路 :

    代码展示 :

    结果分析 :

    解法二(双指针) :

    算法思路 :

    算法流程 :

    图解流程: 

    代码展示 :

    结果分析 :

    4.总结 :


1. 题目链接:

OJ链接:. - 力扣(LeetCode)

2.题目描述 :

购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。

示例 1:

输入:price = [3, 9, 12, 15], target = 18
输出:[3,15] 或者 [15,3]

示例 2:

输入:price = [8, 21, 27, 34, 52, 66], target = 61
输出:[27,34] 或者 [34,27]

提示:

  • 1 <= price.length <= 10^5
  • 1 <= price[i] <= 10^6
  • 1 <= target <= 2*10^6

3.解法 :

    解法一(暴力枚举) :

    算法思路 :

这道题的暴力枚举是最容易想到的方法:

直接定义两个指针,一个指针指向首元素,一个指针指向下一个元素,遍历完整个数组,找到所有方案,直到有一个方案等于target

注意:

还是一样,算法题的数据范围很重要!

提示:

  • 1 <= price.length <= 10^5
  • 1 <= price[i] <= 10^6
  • 1 <= target <= 2*10^6

这道题数组的长度在10^5之内,而我们的暴力枚举时间复杂度为O(N^2),数据量为10^10级别,肯定会超时,不过这里还是写一下,实在没办法可以拿暴力过一些例子分.

    代码展示 :

class Solution {
public:
    vector<int> twoSum(vector<int>& price, int target) {
        for(int i = 0; i < price.size(); i++)
            for(int j = i + 1; j < price.size(); j++)
                if(price[i] + price[j] == target) return {price[i], price[j]};

        return {-1, -1};
    }
};

 

    结果分析 :

不出所料,暴力算法终究还是通过不了,时间超出了限制

每次知道暴力通关不了还去探究的原因:

1. 暴力算法是最好想的方法,可以帮助我们快速分析题目

2. 有的暴力算法优化一下,可能会过(这种情况很少)

3. 如果算法题有例子分的话(蓝桥杯),实在不会,无脑暴力

所以大家做算法题做不出来时,不防使用一下暴力算法,特别是对有些找规律的题目,可以先用暴力枚举将所有例子打印出来,在具体分析

    解法二(双指针) :

    算法思路 :

注意:本题是升序的数组,因此可以用「对撞指针」优化时间复杂度。

    算法流程 :

a. 初始化left, right分别指向数组的左右两端(这里不是我们理解的指针,而是数组的下标)

b. 当left < right的时候,一直循环

        i. 当price[left]  + price[right] == target时,说明找到结果,记录结果,并且返回;

        ii. 当price[left] + price[right] < target时:

                <1>. 对于price[left]而言,此时price相当于是price[left]能碰到的最大值(别忘了,这里是升序数组哈~).如果此时不符合要求,说明在这个数组里面,因此,我们可以大胆舍去这个数,让left++,去比较下一组数据;

                <2>那对于price[right]而言,由于此时两数之和是小于目标值的,price[right]还可以选择比price[left]大的值继续努力达到目标值,因此right指针我们按兵不动;

        iii. 当price[left] + price[right] > target时,同理我们可以舍去,price[right](最小的数都满足不了你,你也没救了).让right--,继续比较下一组数据,而left指针不变(因为他还是可以去匹配比price[right]更小的数).

    图解流程: 

初始情况:

进行判断: 

此时price[left] + price[right] < target:

而我们的right是数组中最大的数,那么left加right之前的数绝对不可能会等于target

所以left++

 这里的情况和上面一样,left++

 进行判断:

此时price[left] + price[right] > target:

left右边的数一定会大于等于11,也就是说left右边的数price[left] + price[right] > target,所以left右边就没必要遍历下去

right--;

 进行判断:

此时price[left] + price[right] == target:

这里我们就找到了合成目标target的两个数返回即可

条件判断总结:

 

    代码展示 :

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

 

    结果分析 :

个人感觉如果算法题中含有单调问题,大家不妨尝试使用双指针去解决问题!!!

    4.总结 :

时间复杂度分析:

这道题使用双指针时间复杂度仅仅为O(N),可以算的上是最优有解法了

空间复杂度分析:

在空间上我们只开辟了两个常量指针,所以空间复杂度为O(1)

 

  • 20
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值