[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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | # 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 题目汇总
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步