[LeetCode] 18. 4Sum 四数之和
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] ]
给一个含有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; }
Java:
public class Solution { int len = 0; public List<List<Integer>> fourSum(int[] nums, int target) { len = nums.length; Arrays.sort(nums); return kSum(nums, target, 4, 0); } private ArrayList<List<Integer>> kSum(int[] nums, int target, int k, int index) { ArrayList<List<Integer>> res = new ArrayList<List<Integer>>(); if(index >= len) { return res; } if(k == 2) { int i = index, j = len - 1; while(i < j) { //find a pair if(target - nums[i] == nums[j]) { List<Integer> temp = new ArrayList<>(); temp.add(nums[i]); temp.add(target-nums[i]); res.add(temp); //skip duplication while(i<j && nums[i]==nums[i+1]) i++; while(i<j && nums[j-1]==nums[j]) j--; i++; j--; //move left bound } else if (target - nums[i] > nums[j]) { i++; //move right bound } else { j--; } } } else{ for (int i = index; i < len - k + 1; i++) { //use current number to reduce ksum into k-1sum ArrayList<List<Integer>> temp = kSum(nums, target - nums[i], k-1, i+1); if(temp != null){ //add previous results for (List<Integer> t : temp) { t.add(0, nums[i]); } res.addAll(temp); } while (i < len-1 && nums[i] == nums[i+1]) { //skip duplicated numbers i++; } } } return res; } }
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
Python:
def fourSum(self, nums, target): def findNsum(nums, target, N, result, results): if len(nums) < N or N < 2 or target < nums[0]*N or target > nums[-1]*N: # early termination return if N == 2: # two pointers solve sorted 2-sum problem l,r = 0,len(nums)-1 while l < r: s = nums[l] + nums[r] if s == target: results.append(result + [nums[l], nums[r]]) l += 1 while l < r and nums[l] == nums[l-1]: l += 1 elif s < target: l += 1 else: r -= 1 else: # recursively reduce N for i in range(len(nums)-N+1): if i == 0 or (i > 0 and nums[i-1] != nums[i]): findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results) results = [] findNsum(sorted(nums), target, 4, [], results) return results
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()); } };
类似题目:
[LeetCode] 454. 4Sum II 四数之和II
All LeetCode Questions List 题目汇总