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)
1. Call 3 sum.public class Solution {
public List> threeSum(int[] nums, int startI, int target) {
int len = nums.length;
List> ret = new ArrayList>();
for(int i = startI; i < len; ++i){
if(i > startI && nums[i-1] == nums[i])
continue;
int x = i+1;
int y = len-1;
while(x < y){
int sum = nums[x] + nums[y] + nums[i];
if(target == sum){
Integer[] res = {nums[x], nums[y], nums[i]};
ret.add(Arrays.asList(res));
--y;
while(y >= startI && nums[y+1] == nums[y]){
--y;
}
++x;
while(x < len && nums[x-1] == nums[x]){
++x;
}
}else if(target < sum){
--y;
while(y >= startI && nums[y+1] == nums[y]){
--y;
}
}else{
++x;
while(x < len && nums[x-1] == nums[x]){
++x;
}
}
}
}
return ret;
}
public List> fourSum(int[] nums, int target) {
int len = nums.length;
List> ret = new ArrayList>();
Arrays.sort(nums);
for( int i = 0; i < len -3; ++i){
if(i > 0 && nums[i-1] == nums[i])
continue;
int j = i+1;
int threeSumTarget = target - nums[i];
List> resThree = threeSum(nums, j, threeSumTarget);
for(List l : resThree){
ArrayList t = new ArrayList(l);
t.add(nums[i]);
Collections.sort(t);
ret.add(t);
}
}
return ret;
}
}
2. Build K Sum
public class Solution {
public List> kSum(int[] nums, int startI, int target, int k) {
int len = nums.length;
List> ret = new ArrayList>();
// List> ret = null can not pass input [0] in 4 sum. All loop return immedicately, including twoSum. It can be controlled by if(4 > len) in main function.
if(2 == k){
// error : forgot to initialize the ret, List> ret = new ... was removed because line 44, ret = kSum(nums, i+1, target - nums[i], k-1);
ret = new ArrayList>();
int i = startI;
int j = len -1;
while(i < j){
int sum = nums[i] + nums[j];
if(sum == target){
List twoSumItem = new ArrayList();
twoSumItem.add(nums[i]);
twoSumItem.add(nums[j]);
ret.add(twoSumItem);
// Here, forgot to increase and decrease index, time limit exceeded. Brain power depleted after 2 hour coding.
++i;
while(i < len && nums[i-1] == nums[i]){
++i;
}
--j;
while(j >= startI && nums[j+1] == nums[j]){
--j;
}
// get the wrong sign, increasing decreasing index with wrong direction, get no answer or little answer.
}else if(sum < target){
++i;
while(i < len && nums[i-1] == nums[i]){
++i;
}
}else{
--j;
while(j >= startI && nums[j+1] == nums[j]){
--j;
}
}
}
return ret;
}
for(int i = startI; i < len; ++i){
if(i > startI && nums[i-1] == nums[i])
continue;
// Tried to optmize code
// Assigned ret as the return from k-1 sums, while forgot k-1 sums were called multiple times, previuos ret were washed out.
/*
ret = kSum(nums, i+1, target - nums[i], k-1);
for(List l : ret){
l.add(nums[i]);
}
*/
List> kMOneRes = kSum(nums, i+1, target - nums[i], k-1);
for(List l : kMOneRes){
l.add(nums[i]);
}
ret.addAll(kMOneRes);
}
return ret;
}
public List> fourSum(int[] nums, int target) {
int len = nums.length;
List> ret = new ArrayList>();
if(4 > len)
return ret;
Arrays.sort(nums);
ret = kSum(nums, 0, target, 4);
for(List l : ret){
Collections.sort(l);
}
return ret;
}
}
3. Pariwise, them two sum. Good solution, reduce complexity to O(N^2), but it is not easy to handle replicated answer. Plus, it can be O(n^4) in worst case. Consider 0 0 0 0 0 1 1 1 1 1, target 1. HashMap : 0: (0, 0) ... , 1: (0, 1) ... , 2 : (1, 1) .... For each key, it contains a list with length O(n^2), Then for target 1 = key 0 + key 1, do pair-wise match between two O(n^2) lists. Could we remove duplicates before hand? It does not sounds possible. Another solution could be divide 4 sum into 0 + 4, 1 + 3, 2 + 2, 3 + 1, 4 + 0 then conquer?
3.
3.
No comments:
Post a Comment