Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
- Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
- The solution set must not contain duplicate quadruplets.
For example, given array S = {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)
给一个含有n个整数的数组S, 找出所有不重复的4个数和等于target的所有解。
解法1:Two pointers, 跟3Sum差不多,只是扩展到4个数字的和。还是按照3Sum的解法,先排序,只是在外面套一层循环,相当于求n次3Sum,用set()去重。3Sum的时间复杂度是O(n^2),所以总时间复杂度O(n^3)。但这个时间复杂度高,用时太长。
解法2:Hash map, 以空间换时间,首先建立一个Hash map,key值为数组中每两个元素的和,对应的value为这两个元素的下标组成的元组num[p]+num[q]] : (p,q) ,pairs元组不一定是唯一的。如对于num=[1,2,3,2]来说,dict={3:[(0,1),(0,3)], 4:[(0,2),(1,3)], 5:[(1,2),(2,3)]}。这样就可以检查target-key这个值在不在dict的key值中,如果target-key在dict中并且下标符合要求,那么就找到了这样的一组解。用set()去重。
Java: 2 pointers
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) { Arrays.sort(num); HashSet<ArrayList<Integer>> hashSet = new HashSet<ArrayList<Integer>>(); ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); for (int i = 0; i < num.length; i++) { for (int j = i + 1; j < num.length; j++) { int k = j + 1; int l = num.length - 1; while (k < l) { int sum = num[i] + num[j] + num[k] + num[l]; if (sum > target) { l--; } else if (sum < target) { k++; } else if (sum == target) { ArrayList<Integer> temp = new ArrayList<Integer>(); temp.add(num[i]); temp.add(num[j]); temp.add(num[k]); temp.add(num[l]); if (!hashSet.contains(temp)) { hashSet.add(temp); result.add(temp); } k++; l--; } } } } return result; }
Python: Two pointers, Time: O(n^3), Space: O(1)
# Two pointer solution. (1356ms) class Solution(object): def fourSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[List[int]] """ nums.sort() res = [] for i in xrange(len(nums) - 3): if i and nums[i] == nums[i - 1]: continue for j in xrange(i + 1, len(nums) - 2): if j != i + 1 and nums[j] == nums[j - 1]: continue sum = target - nums[i] - nums[j] left, right = j + 1, len(nums) - 1 while left < right: if nums[left] + nums[right] == sum: res.append([nums[i], nums[j], nums[left], nums[right]]) right -= 1 left += 1 while left < right and nums[left] == nums[left - 1]: left += 1 while left < right and nums[right] == nums[right + 1]: right -= 1 elif nums[left] + nums[right] > sum: right -= 1 else: left += 1 return res
Python: HashMap, Time: O(n^2 * p), Space: O(n^2 * p)
# Hash solution. (224ms) class Solution2(object): def fourSum(self, nums, target): """ :type nums: List[int] :type target: int :rtype: List[List[int]] """ nums, result, lookup = sorted(nums), [], collections.defaultdict(list) for i in xrange(0, len(nums) - 1): for j in xrange(i + 1, len(nums)): is_duplicated = False for [x, y] in lookup[nums[i] + nums[j]]: if nums[x] == nums[i]: is_duplicated = True break if not is_duplicated: lookup[nums[i] + nums[j]].append([i, j]) ans = {} for c in xrange(2, len(nums)): for d in xrange(c+1, len(nums)): if target - nums[c] - nums[d] in lookup: for [a, b] in lookup[target - nums[c] - nums[d]]: if b < c: quad = [nums[a], nums[b], nums[c], nums[d]] quad_hash = " ".join(str(quad)) if quad_hash not in ans: ans[quad_hash] = True result.append(quad) return result
C++: 2 pointers
class Solution { public: vector<vector<int> > fourSum(vector<int> &nums, int target) { set<vector<int> > res; sort(nums.begin(), nums.end()); for (int i = 0; i < int(nums.size() - 3); ++i) { for (int j = i + 1; j < int(nums.size() - 2); ++j) { int left = j + 1, right = nums.size() - 1; while (left < right) { int sum = nums[i] + nums[j] + nums[left] + nums[right]; if (sum == target) { vector<int> out; out.push_back(nums[i]); out.push_back(nums[j]); out.push_back(nums[left]); out.push_back(nums[right]); res.insert(out); ++left; --right; } else if (sum < target) ++left; else --right; } } } return vector<vector<int> > (res.begin(), res.end()); } };