Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.thealgorithms.backtracking;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/** Backtracking: pick/not-pick with reuse of candidates. */
public final class CombinationSum {
private CombinationSum() {
throw new UnsupportedOperationException("Utility class");
}

public static List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> results = new ArrayList<>();
if (candidates == null || candidates.length == 0) {
return results;
}

// Sort to help with pruning duplicates and early termination
Arrays.sort(candidates);
backtrack(candidates, target, 0, new ArrayList<>(), results);
return results;
}

private static void backtrack(int[] candidates, int remaining, int start, List<Integer> combination, List<List<Integer>> results) {
if (remaining == 0) {
// Found valid combination; add a copy
results.add(new ArrayList<>(combination));
return;
}

for (int i = start; i < candidates.length; i++) {
int candidate = candidates[i];

// If candidate is greater than remaining target, further candidates (sorted) will also be too big
if (candidate > remaining) {
break;
}

// include candidate
combination.add(candidate);
// Because we can reuse the same element, we pass i (not i + 1)
backtrack(candidates, remaining - candidate, i, combination, results);
// backtrack: remove last
combination.remove(combination.size() - 1);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.thealgorithms.backtracking;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import org.junit.jupiter.api.Test;

class CombinationSumTest {
private static List<List<Integer>> norm(Iterable<List<Integer>> x) {
List<List<Integer>> y = new ArrayList<>();
for (var p : x) {
var q = new ArrayList<>(p);
q.sort(Integer::compare);
y.add(q);
}
y.sort(Comparator.<List<Integer>>comparingInt(List::size).thenComparing(Object::toString));
return y;
}

@Test
void sample() {
int[] candidates = {2, 3, 6, 7};
int target = 7;
var expected = List.of(List.of(2, 2, 3), List.of(7));
assertEquals(norm(expected), norm(CombinationSum.combinationSum(candidates, target)));
}
}