文章目录
- 和为S的两个数
- 题目解析
- 算法原理
- 代码
- 三数之和
- 题目解析
- 算法原理
- 代码
- 四数之和
- 题目解析
- 算法原理
- 代码
和为S的两个数
题目解析
【题目链接】
该题目的原题为和为s的两个数:
即给定一组升序数据(数组price),并给出一个变量target,要求找出和为target的两个数;
算法原理
-
暴力枚举
暴力枚举顾名思义就是暴力解法,使用两个for循环枚举出所有的可能并做出判断;
for(i) { for(j) { check(i+j==target?) } }
-
双指针
该双指针的解法即为创建两个指针分别为
left
与right
分别指向0
与price.size()-1
的位置;由于数据已经是升序已经具有单调性,所以不需要再进行排序;
left+right
每次的结果sum
共有三种可能性:sum>target
;sum<target
sum==target
若是
sum>target
则表示right
数据较大,应该--right
;若是
sum<target
则表示left
数据较小,应该++left
;否则则相等,返回对应的
left
与right
所对应的值;
代码
-
双指针
class Solution { public: vector<int> twoSum(vector<int>& price, int target) { int first = 0; int last = price.size()-1; while(first<last){ if(price[first]+price[last]>target) --last; else if(price[first]+price[last]<target) ++first; else return {price[first],price[last]}; } return {1,2}; } };
三数之和
题目解析
【题目链接】
本题的关键信息:
-
a
,b
,c
三数之和为0
; -
不重复的三元组
以示例1为例,三元组为
[-1,0,1]
,[-1,0,1]
,[-1,-1,2]
;但最终答案为[
[-1,0,1]
,[-1,-1,2]
];
算法原理
-
双指针
该算法原理可以参考上一题
和为S的两个数
,具体的思路为将数组首先进行一次排序使其具有单调性;再通过
和为S的两个数
的思路进行;具体为:
-
固定好一个数据(最左),在该数据的右侧区间内找到和为该数的相反数的两个数;
-
由于需要找到数组中所有这样的数据,所以在找到一组数据后应该继续找;
同时在该题中应该要特别注意一个细节:
- 去重
该数据中返回的所有三元组和都将是不重复的,具体的去重方法有两种:
-
使用unordered_set容器进行去重;
-
控制指针,当指针所指数据与上一位置数据相同则会出现三元组重复的可能;
所以分别控制
cur
,lefy
,right
指针即可;
小优化:由于数据经排序后已经具有单调性,所以当
cur
所指位置数据>0时,则代表cur后区间的数据中已经不满足三数之和>0,所以cur
所指位置数据>0时,可以直接跳出循环; -
代码
- 双指针
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(),nums.end());//排序使数组具有单调性
int len = nums.size();
int cur = 0;
while(cur<nums.size()){//固定一个数据
if(nums[cur]>0) break;//当cur数据>0时则表示该指针后的区间不存在符合条件的三元组
//定义变量
int left = cur+1;//left指针所在数据为cur指针后一个位置
int right = nums.size()-1;
int targe = -nums[cur];//变量targe用于存储cur所指数据的相反数,用来与左右数据之和进行比较
while(left < right){
int sum = nums[left] + nums[right];
if(sum > targe) --right;
else if(sum < targe) ++left;
else{
ret.push_back({nums[cur],nums[left],nums[right]});
++left,--right;//存入一组数据之后应该继续遍历
//对left,right指针进行去重
while(left<right && nums[left-1] == nums[left]) ++left;
while(left<right && nums[right+1] == nums[right]) --right;
}
}
++cur;
while(cur<nums.size()&&nums[cur] == nums[cur-1]) ++cur;//对cur进行去重
}
return ret;
}
};
四数之和
题目解析
【题目链接】
算法原理
-
双指针
该题的双指针的思路与
三数之和
题目大差不差,与之不同的是多一层循环用来固定双指针外的另一个数;
代码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());//排序使其具有单调性
vector<vector<int>> ret;
int len = nums.size();
for(int i = 0;i<len;){
for(int j = i+1;j<len;){
int left = j + 1;
int right = len - 1;
long long tmp = (long long)target - nums[i] - nums[j];//long long类型为对测试用例的进行特殊处理
while(left<right){
int sum = nums[left]+nums[right];
if(sum>tmp) right--;
else if(sum<tmp) left++;
else {
ret.push_back({nums[left],nums[right],nums[i],nums[j]});
left++,right--;//继续遍历
//去重左右
while(left<right && nums[left] == nums[left-1]) ++left;
while(left<right && nums[right] == nums[right+1]) --right;
}
}
//指针j的去重
++j;
while(j<len&&nums[j] == nums[j-1]) ++j;
}
//指针i的去重
++i;
while(i<len&&nums[i] == nums[i-1]) ++i;
}
return ret;
}
};