个人主页: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)