Link: https://oj.leetcode.com/problems/4sum/
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)Approach I: 我的思路:同3Sum, 先排序,然後左右夾逼。
Time: O(n^3)
public class Solution {
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
Arrays.sort(num);
for(int i = 0; i < num.length; i++){
if(i != 0 && num[i] == num[i-1]) continue;
int remain = target - num[i];
ArrayList<Integer> item = new ArrayList<Integer>();
item.add(num[i]);
ArrayList<ArrayList<Integer>> sub = threeSum(num, i+1, remain);
for(int j = 0; j <sub.size(); j++){
for(int k = 0; k < sub.get(j).size();k++){
item.add(sub.get(j).get(k));
}
}
result.add(item);
}
return result;
}
public ArrayList<ArrayList<Integer>> threeSum(int[] num, int l, int target){
ArrayList<ArrayList<Integer>> sub = new ArrayList<ArrayList<Integer>> ();
for(int i = l; i < num.length; i++){
if(i != l && num[i] == num[i-1]) continue;
int j = i+1;
int k = num.length - 1;
while(j < k){
if(num[j]+num[k] == target - num[i]){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(num[i]);
list.add(num[j]);
list.add(num[k]);
sub.add(list);
j++;
k--;
while(j < k && num[j] == num[j-1]){
j++;
}
while(j < k && num[k] == num[k+1]){
k--;
}
}
else if(num[j]+num[k] < target -num[i]){
j++;
}
else{
k--;
}
}
}
return sub;
}
}
I don't know why did I have wrong answer:
Input: | [0], 0 |
Output: | [[0]] |
Expected: | [] |
但是寫成這樣就可以過:516ms
public class Solution {
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if(num==null||num.length==0)
return result;
Arrays.sort(num);
for(int l = 0; l < num.length;l++){
if(l != 0 && num[l] == num[l-1]) continue;
for(int i = l+1; i < num.length; i++){
if(i != l+1 && num[i] == num[i-1]) continue;
int j = i+1;
int k = num.length - 1;
while(j < k){
if(num[l] + num[i] + num[j]+num[k] == target){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(num[l]);
list.add(num[i]);
list.add(num[j]);
list.add(num[k]);
result.add(list);
j++;
k--;
while(j < k && num[j] == num[j-1]){
j++;
}
while(j < k && num[k] == num[k+1]){
k--;
}
}
else if(num[l] + num[i] + num[j]+num[k] < target){
j++;
}
else{
k--;
}
}
}
}
return result;
}
}
Approach II: 4Sum = TwoSum + TwoSum. 先找出所有的pair (O(n^2)),然後對這些pair進行TwoSum。
Time = O(n^2log(n^2))= O(n^2logn)
I tried to complete the code from Ref:
but didn't finish.
public class Solution {
public class Tuple{
ArrayList<Integer> val;
public Tuple(ArrayList<Integer> val){
this.val = val;
}
}
public class Pair{
Nodes[] nodes;
public Pair (Node n1, Node n2){
nodes = new Node[2];
nodes[0] = n1;
nodes[1] = n2;
}
publc int getSum(){
return nodes[0].val + nodes[1].val;
}
}
public class Node{
int index;
int val;
public Node(int index, int val){
this.index = index;
this.val = val;
}
}
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
if(num==null||num.length==0)
return result;
Arrays.sort(num);
//save all the pairs into an ArrayList
ArrayList<Pair> pairs = new ArrayList<Pair>();
Pair p = null;
for(int i = 0; i < num.length; i++){
Node n1 = new Node(i, num[i]);
for(int j = i+1; j < num.length; j++){
Node n2 = new Node(j, num[j]);
p = new Pair(n1, n2);
pairs.add(p);
}
}
pairs.sort(pair, new Comparator<Pair>(){
public int compare(Pair p1, Pair p2){
if(p1.getSum() < p2.getSum()){
return 1;
}
else if(p1.getSum() == p2.getSum()){
return 0;
}
else return -1;
}
}
result = twoSum(pairs, target);
return result;
}
private ArrayList<ArrayList<Integer>> twoSum(ArrayList<Pair> pairs, int target) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
HashSet<Tuple> set = new HashSet<Tuple>();
int i = 0;
int j = pairs.size()-1;
while(i < j){
int sum = pairs.get(i).getSum() + pairs.get(i).getSum();
if(sum == target){
ArrayList<Integer> list = new ArrayList<Integer>();
if(checkDup(pairs.get(i), pairs.get(i))){
list.add(pairs.get(i).nodes[0].val);
list.add(pairs.get(i).nodes[1].val);
list.add(pairs.get(j).nodes[0].val);
list.add(pairs.get(j).nodes[1].val);
Tuple t = new Tuple(list);
if(!set.contains(t)){
set.add(t);
result.add(list);
}
}
}
else if (sum < target){
i++;
}
else{
j--;
}
}
}
private boolean checkDup(Pair p1, Pair p2){
if(p1.node[0].index == p2.nodes[0].index || p1.node[0].index == p2.nodes[1].index){
return false;
}
if(p1.node[1].index == p2.nodes[0].index || p1.node[1].index == p2.nodes[1].index){
return false;
}
return true;
}
}
Pass OJ version:
Ref: http://www.lifeincode.net/programming/leetcode-two-sum-3-sum-3-sum-closest-and-4-sum-java/
Note: 雖然這個解法的時間複雜度小,但用時更長:804ms
public class Solution {
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
Arrays.sort(num);
//create a hashmap of <sum, (idx1, idx2)>
HashMap<Integer, ArrayList<ArrayList<Integer>>> dict = new HashMap<Integer, ArrayList<ArrayList<Integer>>>();
ArrayList<ArrayList<Integer>> pairs = new ArrayList<ArrayList<Integer>>();
for(int i = 0; i < num.length - 1; i++){
for(int j = i+1; j < num.length; j++){
ArrayList<Integer> pair = new ArrayList<Integer>(2);
pair.add(i);
pair.add(j);
int sum = num[i] + num[j];
if(!dict.containsKey(sum)){
pairs = new ArrayList<ArrayList<Integer>>();
pairs.add(pair);
dict.put(sum, pairs);
}
else{
pairs = dict.get(sum);
pairs.add(pair);
}
}
}
//create hashset to prevent duplicate results
HashSet<ArrayList<Integer>> set = new HashSet<ArrayList<Integer>> ();
for(Integer sum : dict.keySet()){//Note: Remember this line's format!
pairs = dict.get(sum);
if(dict.containsKey(target - sum)){//found the other half
if(target - sum == sum && dict.get(sum).size()==1){//6=3+3.why is dict.get(sum).size()==1 possible?
continue;
}
ArrayList<ArrayList<Integer>> otherPairs = dict.get(target - sum);
for(ArrayList<Integer> p1 : pairs){
for(ArrayList<Integer> p2 : otherPairs){
if(p1 == p2) continue;
if(p1.contains(p2.get(0)) ||p1.contains(p2.get(1))){
continue;
}
ArrayList<Integer> tmpResult = new ArrayList<Integer>(4);
tmpResult.add(num[p1.get(0)]);
tmpResult.add(num[p1.get(1)]);
tmpResult.add(num[p2.get(0)]);
tmpResult.add(num[p2.get(1)]);
//sort the list since require non-descending order
Collections.sort(tmpResult);
set.add(tmpResult);
}
}
}
}
result.addAll(set);
return result;
}
}
注意:如果不用hashset,而是直接把結果放到arraylist裏,會出現錯誤。爲什麼?
Input: |
Output: |
Expected: |