三数之和
(1)排序+双指针
算法思路: 和之前的两数之和类似,我们对暴力枚举进行了一些优化,利用了排序+双指针的思路:
我们先排序,然后固定⼀个数 a ,接着我们就可以在这个数后面的区间内,使用之前两数之和使用的算法,快速找到两个数之和和固定的a等于target即可。
但是要注意,为了避免其中有重复的解:
我们需要在找到⼀个结果之后, left 和 right 指针要跳过重复的元素;同时在使用完一次双指针算法之后,固定的 a 也要跳过重复的元素。
算法实现过程:
给定一个包含n个整数的数组nums,函数返回所有不重复的三元组[a, b, c],使得a + b + c = 0。函数首先对数组进行排序,然后使用双指针的方法来遍历数组。外层循环通过变量i遍历数组,内层循环通过变量left和right来找到满足条件的三元组。
如果三数之和小于0,则将left右移一位;如果大于0,则将right左移一位;如果等于0,则将三个数加入结果数组ret,并继续移动left和right直到找到不重复的三元组。最后,返回结果数组ret。
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(),nums.end());//排序vector<vector<int>> ret;//定义一个二维数组int n=nums.size();for(int i=0;i<n;){int left=i+1;int right=n-1;if(nums[i]>0) break;//如果最小值大于0,那结果一定大于0while(left<right){int sum=nums[i]+nums[left]+nums[right];if(sum<0) left++;//三数之和小于0,left++else if(sum>0) right--;//三数之和大于0,right--else {ret.push_back({nums[i],nums[left],nums[right]});left++;//找到了一组解后,left和right都要改变right--;//避免重复的解while(left<right&&nums[left]==nums[left-1]) left++;while(left<right&&nums[right]==nums[right+1]) right--;}//跳过相同的值,也是为了避免重复的解}i++;//i也要跳过相同的值,而且i不可以越界,所以要i<nwhile(i<n&&nums[i]==nums[i-1]) i++;}return ret;}
};
时间复杂度:O(n2)
四数之和
(1)排序+双指针
实现方式和三数之和类似,固定两个数即可。
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ret;//定义一个二维数组sort(nums.begin(),nums.end());//排序int n=nums.size();for(int i=0;i<n;)//固定第一个数{for(int j=i+1;j<n;)//固定第二个数{int left=j+1;int right=n-1;//后面的测试用例比较大,用long longlong long aim=(long long)target-nums[i]-nums[j];while(left<right){int sum=nums[left]+nums[right];if(sum>aim) right--;//如果四数之和大于目标值,right--else if(sum<aim) left++;//如果四数之和小于目标值,left++else {ret.push_back({nums[i],nums[j],nums[left],nums[right]});left++;//left++,right--,避免有重复的情况right--;//跳过相同的数while(left<right&&nums[left]==nums[left-1]) left++;while(left<right&&nums[right]==nums[right+1]) right--;}}j++;//跳过和第二个数相同的数while(j<n&&nums[j]==nums[j-1]) j++;}i++;//跳过和第一个数相同的数while(i<n&&nums[i]==nums[i-1]) i++;}return ret;}
};
时间复杂度:O(N3)