如题目所示,这篇文章要讲解的三道题是有很大的关联的,循循渐进逐步展开,介绍双指针算法在解决这类题时能带来的优化。
这道题比较简单,也是带入这种题型不错的选择,如题目所说,提供的数组已经是升序,使用暴力解法将所有的两数组合全部遍历一遍,这种解法的时间复杂度为O(N2),而且题目所提供的升序数组也没有用到,素以我们可以借助升序来寻找跟好的算法。
双指针你一定会想到,因为是升序,我们可以用两个指针left和right分别指向数组首位置和末位置,这样就可以知道最大元素和最小元素的和,如果和是大于目标值,就左移right,此时得到的目标值就会减小(因为是升序嘛),如果小于目标值,那就右移left,这样的道德目标值就会变大,这样只需要遍历一遍就可以债哦哦到结果。
以下是C++解法
vector<int> twoSum(vector<int>& price, int target) { int i=0,j=price.size()-1; vector<int> a;//偷懒了i->left j->right while(i!=j) { int sum=price[i]+price[j]; if(sum<target) { i++; } if(sum>target) { j--; } if(sum==target) { break; } } a.push_back(price[i]); a.push_back(price[j]); return a; }
有了前一道题的衬托,我们就可以很轻松的想出这道题的解法,首先还是要介绍暴力解法,三层for循环,遍历出所有符合条件的三元组,但是这道题有很难搞的地方就是不可以包含重复的三元组,所以我们找出所有的三元组之后还需要进行去重操作。
先思考思考如何使用双指针算法思想进行解决,对于第一道题目,有着很重要的条件,那就是升序数组,我们可以找出规律从而简化以减少遍历次数,减小时间复杂度。
所以我们要先将数组排序,返回值类型为二维数组,我们提前构造一个二维数组作为返回值。
此时数组已经是一个升序数组了,我们的目标是找到三个数是他们的和等于0,换一种思路就是找到两个数,使他们的和等于第三个数的负数,这样就回归到两数之和了,首先我们要先锁定一个数,作为第三个数,在剩下的数中找到两个使它们的和等于锁定的数的负数即可,找两个数的操作和第一题的思路一模一样。
如何去重呢?
这是一个比较麻烦的问题。
在找到一组符合要求的值之后,判断left后边的和前边的值是否和已经记录过的相同,如果相同的话,那就跳过相同的数,就可以实现去重操作。不要忘记咯,我们选择的目标值也是要跳过相同的元素(就是目标值也是不同的),这样就切切实实实现了去重操作。
举例说明:
在锁定1之后,后边的1也要全部跳过,在left为-1right为0时,符合条件,但是为了去重,right要跳过所有的1,left要跳过所有的-1,即去重操作。要注意的是,在left前移和right后移的过程中,left保持恒小于right。
这道题目还要注意的点就是返回的对象为二维数组,在打印时可以使用两层for循环。
代码如下
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> a; sort(nums.begin(), nums.end()); int size = nums.size() - 1; for (int i = size; i >= 0; ) { if (nums[i] < 0) { break; } int target = -nums[i]; int right = i - 1; int left = 0; while (left < right) { if (nums[right] + nums[left] > target)right--; else if (nums[right] + nums[left] < target)left++; else {//此时我们找到了符合条件的值 a.push_back({ nums[i],nums[right],nums[left] });//直接将这个三元组插入 left++; right--; //去重操作 while (left < right && nums[left] == nums[left - 1])left++; while (left < right && nums[right] == nums[right + 1])right--; } } i--; while (i > 0 && nums[i] == nums[i + 1]) { i--; } } for (auto i : a) { for (auto s : i) { cout << s << ' '; } cout << endl; } return a; } };