一 题目
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] ]
二 分析
题目是数组4个元素和为指定target。难度是medium级别。
前面做过类似的题目。可以先看看,2sum.入门系列Two Sum 时间复杂度是O(n) 线性的。
leetcode 15. 3Sum ,暴力循环是O(n^3), 使用降维的方式,先排序+滑动窗口,可以做到O(n^2).
同理,对于4sum也可以套用这种方式。时间复杂度O(n^3).比3sum多了一层循环。
public static void main(String[] args) {
int[] nums ={1, 0, -1, 0, -2, 2};
List<List<Integer>> res = fourSum(nums,0);
System.out.println(JSON.toJSON( res) );
}
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> reslist = new ArrayList<List<Integer>>();
if (nums.length < 4) return reslist;
//先排序
Arrays.sort(nums);
for(int i=0;i<= nums.length-4;i++){
for(int j=i+1;j<= nums.length-3;j++){
int left = j+1;
int right = nums.length-1;
while(left< right){
int sum = nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target){
List<Integer> tlist = Arrays.asList(nums[i],nums[j],nums[left],nums[right]);
if(!reslist.contains(tlist)){
reslist.add(tlist);
}
right --;
}
else if(sum>target){
right --;
}else {
left++;
}
}
}
}
return reslist;
}
Runtime: 27 ms, faster than 42.64% of Java online submissions for 4Sum.
Memory Usage: 38 MB, less than 100.00% of Java online submissions for4Sum.
看提交结果,应该有更好的方案。目前已经从O(n^4)降到了O(n^3).
如何更快呢?
hashmap存储两两之和
public static List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> reslist = new ArrayList<List<Integer>>();
if (nums.length < 4) return reslist;
//先排序
Arrays.sort(nums);
//两两求和
Map<Integer,List<Integer[]>> map = new HashMap();
for(int i=0;i<nums.length-1;i++ ){
for(int j=i+1;j< nums.length;j++ ){
Integer[] pair = {i, j};
int tmp = nums[i]+nums[j];
if(!map.containsKey(tmp)){
map.put(tmp, new ArrayList<Integer[]>());
}
map.get(tmp).add(pair);
}
}
//rule
for (int i = 0; i < nums.length-1; i ++)
{
for (int j = i + 1; j < nums.length; j ++)
{
int gap = target - nums[i] - nums[j];
if(!map.containsKey(gap)){//不包含
continue;
}
List<Integer[]> list = map.get(gap);
for(int k=0;k< list.size(); k++){
//有重合
if(i<= list.get(k)[1]){
continue;
}
List<Integer> tlist = new ArrayList<>();
tlist.add(nums[i]);
tlist.add(nums[j]);
tlist.add(nums[list.get(k)[0]]);
tlist.add(nums[list.get(k)[1]]);
if(!reslist.containsAll(tlist)){
reslist.add(tlist);
}
}
}
}
return reslist;
}
我试着提交下,
Runtime: 34 ms, faster than 24.38% of Java online submissions for 4Sum.
Memory Usage: 39 MB, less than 84.06% of Java online submissions for4Sum.
真的不快,应该是我的代码写的有问题,没有达到网上说的那种 平均O(n^2),最坏O(n^4)。
有空在研究下。