Combination Sum
Problem
A list of different positive numbers and a target k are given. Print every way to choose numbers that add up to k. A number can be used any number of times. Inside one line the numbers go from small to big, and the lines are in alphabetical (lexicographic) order of their numbers; a way is not repeated in another order. If there is no way, print none.
Constraints
- 1 <= n <= 10
- 1 <= k <= 30
- numbers are different and positive
Examples
Input
4 2 3 6 7 7
Output
2 2 3 7
Solutions
The loop starts at index start, so the numbers in a way never go down; this removes duplicate ways such as 2 3 2 and 3 2 2. Sorting the numbers also allows an early stop when a number is already too big.
/*
* Problem : Ways to reach the target.
* Input : n, the numbers, then k.
* Output : One way per line.
* Approach: Backtracking.
* Time : O(number of ways * length)
* Space : O(target)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// Step 1: Try the numbers from index "start" on. Going back to a smaller index is not allowed, so no way repeats.
static void search(int[] numbers, int start, int remaining, java.util.ArrayList<Integer> current, java.util.List<String> found) {
// Step 2: Base case. When nothing remains, the current choice is a way.
if (remaining == 0) {
StringBuilder line = new StringBuilder();
for (int i = 0; i < current.size(); i++) {
line.append(i == 0 ? "" : " ").append(current.get(i));
}
found.add(line.toString());
return;
}
for (int i = start; i < numbers.length && numbers[i] <= remaining; i++) {
// Step 3: Choose the number, search again from the same index (reuse is allowed), then remove it (backtrack).
current.add(numbers[i]);
search(numbers, i, remaining - numbers[i], current, found);
current.remove(current.size() - 1);
}
}
// This method solves the task. It receives the input and returns the answer.
static String[] solve(int[] a, int k) {
// Step 4: Sorting lets us stop early and gives the lines in lexicographic order.
int[] numbers = a.clone();
java.util.Arrays.sort(numbers);
java.util.List<String> found = new java.util.ArrayList<>();
search(numbers, 0, k, new java.util.ArrayList<>(), found);
if (found.isEmpty()) {
return new String[] {"none"};
}
return found.toArray(new String[0]);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int size = scanner.nextInt();
int[] a = new int[size];
for (int i = 0; i < size; i++) {
a[i] = scanner.nextInt();
}
int k = scanner.nextInt();
System.out.println(String.join("\n", solve(a, k)));
}
}
Hints (1)
- Why does the recursive call pass i and not i + 1?