15. 3Sum
Two Sum 的 follow up
Two Sum 使用hashtable做到O(n)时间复杂度
所以看到这道题,第一想法是固定一个元素,剩下的用 Two Sum 处理。但是由于这道题有重复元素存在,最后去重会TLE,因此不能这样做。
在一个有序数组里寻找加和为给定值的两个元素,我们可以使用 Two Pointers 从两侧向中间来寻找。
对于这道题,我们可以先对数组进行排序,固定一个数nums[i],用 Two Pointers 寻找加和等于 -nums[i] 的两个数。每次两个pointer都跳过重复的元素,固定的nums[i]也跳过重复的元素,这样最后答案里所有的解都是唯一的了。
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; sort(nums.begin(),nums.end()); for (int i=0;i<nums.size();++i){ int target= -nums[i]; int low=i+1, high=nums.size()-1; while (low<high){ int sum=nums[low]+nums[high]; if (sum<target) ++low; else if (sum>target) --high; else{ vector<int> tri({nums[i],nums[low],nums[high]}); res.push_back(tri); //skip the same value as nums[low] while (low<high && nums[low]==tri[1]) ++low; //skip the same value as nums[high] while (low<high && nums[high]==tri[2]) --high; } } //skip the same value as nums[i] while (i+1<nums.size() && nums[i+1]==nums[i]) ++i; } return res; } };
16. 3Sum Closest
和 3 Sum 几乎一模一样,复习一下。
class Solution { public: int threeSumClosest(vector<int>& nums, int target) { if (nums.size()<3) return 0; int res=nums[0]+nums[1]+nums[2]; sort(nums.begin(),nums.end()); for (int i=0;i<nums.size();++i){ if (i>=1 && nums[i]==nums[i-1]) continue; int low=i+1, high=nums.size()-1; while (low<high){ int curSum=nums[i]+nums[low]+nums[high]; if (curSum==target) return curSum; if (abs(curSum-target)<abs(res-target)) res = curSum; if (curSum<target) ++low; else if (curSum>target) --high; } } return res; } };
259. 3Sum Smaller
curSum<target 时,low不变,high从high到low+1都是可行的,所以+=high-low。
class Solution { public: int threeSumSmaller(vector<int>& nums, int target) { int cnt=0; sort(nums.begin(),nums.end()); for (int i=0;i<nums.size();++i){ int low=i+1, high=nums.size()-1; while (low<high){ int curSum=nums[i]+nums[low]+nums[high]; if (curSum<target){ cnt += high-low; // the third num can be any element in (low,high] ++low; }else --high; } } return cnt; } };
18. 4Sum
还是一样的套路,把之前的写法跟精简了一下:
class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> res; sort(nums.begin(),nums.end()); for (int i=0;i<nums.size();++i){ if (i>0 && nums[i]==nums[i-1]) continue; for (int j=i+1;j<nums.size();++j){ if (j>i+1 && nums[j]==nums[j-1]) continue; int low=j+1, high=nums.size()-1; while (low<high){ int sum=nums[i]+nums[j]+nums[low]+nums[high]; if (sum==target){ res.push_back({nums[i],nums[j],nums[low],nums[high]}); ++low; --high; while (low<high && nums[low]==nums[low-1]) ++low; while (low<high && nums[high]==nums[high+1]) --high; }else if (sum<target) ++low; else --high; } } } return res; } };