【Leetcode】15、3Sum && 16、3Sum Closest && 18、4Sum
题目一
Given an array nums
of n integers, are there elements a, b, c in nums
such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
思路
如果数组是无序的,很难有比O(N3)更好的办法。除非是用哈希表,在得到两个数之和之后,在表中O(1)时间内寻找第三个数,总体复杂度也是O(n2),但需要O(n)的空间。
如果先将数组排序O(nlogn),然后固定第一个数,在后面的部分用TwoSum和数组递增的思想,来搜索。总体时间复杂度为O(nlogn+n2)
需要注意的是最后结果中不能有重复的。
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; int len = nums.size(); if (len <= 2) return res; sort(nums.begin(), nums.end()); int i = 0; while (i < len) { int start = i + 1; int end = len - 1; while (start < end) { if (nums[i] + nums[start] + nums[end] == 0){ res.push_back({nums[i], nums[start], nums[end]}); start++; end--; while (start < end && nums[start] == nums[start-1]) start++; while (start < end && nums[end] == nums[end+1]) end--; } else if (nums[i] + nums[start] + nums[end] > 0) end--; else start++; } i++; // 防止重复,不能删去 while (i < len && nums[i] == nums[i-1]) i++; } return res; } };
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; int len = nums.size(); if (len <= 2) return res; sort(nums.begin(), nums.end()); int i = 0; for (int i = 0; i < len - 2; i++) { if(i>0 && nums[i] == nums[i-1]) // 防止重复 continue; if(nums[i] + nums[i+1] + nums[i+2] > 0) // 减小搜索空间 break; if(nums[i] + nums[len-2] + nums[len-1] + nums[len-1] < 0) // 存在和为的3Sum continue; int start = i + 1; int end = len - 1; while (start < end) { if (nums[i] + nums[start] + nums[end] == 0){ res.push_back({nums[i], nums[start], nums[end]}); start++; end--; while (start < end && nums[start] == nums[start-1]) start++; while (start < end && nums[end] == nums[end+1]) end--; } else if (nums[i] + nums[start] + nums[end] > 0) end--; else start++; } } return res; } };
题目二
Given an array nums
of n integers and an integer target
, find three integers in nums
such that the sum is closest to target
. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
Given array nums = [-1, 2, 1, -4], and target = 1. The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
思路
整体框架和题目一差不多,只需要多一个变量来记录当前的 sum-target 是否比之前的更小即可。
class Solution { public: int threeSumClosest(vector<int>& nums, int target) { int len = nums.size(); int res = nums[0] + nums[1] + nums[len - 1]; sort(nums.begin(), nums.end()); for (int i = 0; i < len - 2; i++) { int start = i + 1, end = len - 1; while (start < end) { int sum = nums[i] + nums[start] + nums[end]; if (sum > target) end--; else start++; if (abs(sum - target) < abs(res - target)) res = sum; } } return res; } };
题目3
Given an array nums
of n integers and an integer target
, are there elements a, b, c, and d in nums
such that a + b + c + d = target
? Find all unique quadruplets in the array which gives the sum of target
.
Note:
The solution set must not contain duplicate quadruplets.
Example:
Given array nums = [1, 0, -1, 0, -2, 2], and target = 0. A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
思路
和3Sum完全相同,还是转化为2Sum的问题
class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> res; int len = nums.size(); if (len < 4) return res; sort(nums.begin(), nums.end()); for(int i = 0; i < len-3; i++) { // 每次会减少一些搜索空间 if(i > 0 && nums[i] == nums[i-1]) continue; if(nums[i] + nums[i+1] + nums[i+2] + nums[i+3] > target) break; if(nums[i] + nums[len-3] + nums[len-2] + nums[len-1] < target) continue; for(int j = i + 1; j < len-2; j++) { // 减小搜索空间 if(j > i+1 && nums[j] == nums[j-1]) continue; if(nums[i] + nums[j] + nums[j+1] + nums[j+2] > target) break; if(nums[i] + nums[j] + nums[len-2] + nums[len-1] < target) continue; int left=j + 1,right = len - 1; while(left < right){ int sum = nums[left] + nums[right] + nums[i] + nums[j]; if(sum < target) left++; else if(sum > target) right--; else{ res.push_back({nums[i],nums[j],nums[left],nums[right]}); left++; right--; while(nums[left] == nums[left-1] && left < right) left++; while(nums[right] == nums[right+1] && left < right) right--; } } } } return res; } };