import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
/**
* 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)
*
* Tags: Array, HashTable, Two pointers
*/
class FourSum {
public static void main(String[] args) {
}
/**
* Four pointers, O(n^3) time
* First pointer i starts from 1 to num.length - 4, 3 indices remain
* Second pointer j starts from i + 1 to num.length - 3, 2 indices remain
* Then get newTarget and search from both ends of the remaining numbers
* Skip duplicate every time
*/
public List<List<Integer>> fourSum(int[] num, int target) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (num == null || num.length < 4) return res;
Arrays.sort(num);
for (int i = 0; i < num.length - 3; i++) { // 3 indices remain
if (i > 0 && num[i] == num[i - 1]) continue; // skip duplicate
for (int j = i + 1; j < num.length - 2; j++) { // 2 indices remain
if (j > i + 1 && num[j] == num[j - 1]) continue; // skip
int newTar = target - num[i] - num[j]; // 2 sum
int l = j + 1;
int r = num.length - 1;
while (l < r) {
if (l > j + 1 && num[l] == num[l - 1]) { // skip
l++;
continue;
}
if (r < num.length - 1 && num[r] == num[r + 1]) { // skip
r--;
continue;
}
int sum = num[l] + num[r];
if (sum < newTar) l++;
else if (sum > newTar) r--;
else { // sum == newTar
res.add(new ArrayList<Integer>(Arrays.asList(num[i], num[j], num[l], num[r])));
l++;
r--;
}
}
}
}
return res;
}
}