import java.util.*;
/**
* Given an array S of n integers, are there K elements (e.g., a, b, c, d, e …
* totally K elements) in S such that their sum equal to a given target? Find
* all such unique K elements tuple(a, b, c, d, e, …) in the array which gives
* the given target.
*
* Tags: Array, Two Pointers, Backtracking
*/
class KSum {
public static void main(String[] args) {
KSum r = new KSum();
int[] num = { 7, 2, 5, 1, 6, 3, 8, 9, 10, 4 };
int k = 6;
int target = 24;
List<List<Integer>> res = r.kSum(num, k, target);
for (List<Integer> l : res) System.out.println(l);
}
/**
* Sort num array first
*/
public List<List<Integer>> kSum(int[] num, int k, int target) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (num == null || num.length == 0 || num.length < k) return res;
Arrays.sort(num); // sort first
return kSum(num, k, target, 0);
}
/**
* Backtracking
* Base case when k == 2, use 2 pointers and add it to result
* If k > 2, from position to the end of array
* Get k - 1 sum from recursive call first
* Then combine current number with results of k-1 sum and add to result
*/
public List<List<Integer>> kSum(int[] num, int k, int target, int pos) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if (k == 2) { // base case, k == 2
int i = pos;
int j = num.length - 1;
while (i < j) {
if (i > pos && num[i] == num[i - 1]) { // skip duplicates
i++;
continue;
}
int sum = num[i] + num[j];
if (sum == target) {
List<Integer> tuple = new ArrayList<Integer>();
tuple.add(num[i]);
tuple.add(num[j]);
i++;
j--;
res.add(tuple);
}
else if (sum > target) j--;
else i++;
}
return res;
}
// k > 2
for (int i = pos; i < num.length; i++) {
if (i > pos && num[i] == num[i - 1]) continue; // skip duplicates
List<List<Integer>> k1Sum = kSum(num, k-1, target - num[i], i+1); // get k-1 sum from recursive calls
for (List<Integer> s : k1Sum) {
List<Integer> tuple = new ArrayList<Integer>();
tuple.add(num[i]); // add current element
tuple.addAll(s); // add k-1 sum
res.add(tuple);
}
}
return res;
}
}