Skip to content

Commit 2568b96

Browse files
alxkmvil02
andauthored
Adding class for generating all subsequences from a given List (#5194)
* Adding class for generating all subsequences from a given List * Fix test data format * Fix braces wrong placement * Fix "Utility classes should not have a public or default constructor." * Fix checkstyle " Class Subsequence should be declared as final." * Renaming class Subsequence to SubsequenceFinder. Refactored test to Parametrized test. Fixed input parameter as final. * Fix formatting * Fix formatting * Fix formatting * Fix import ordering * Renaming method generate all. Renaming test method. Adding duplication test. Renaming TestData to TestCase. * Fix formatting * style: add assertion to avoid potential infinite loop --------- Co-authored-by: Piotr Idzik <[email protected]>
1 parent a6e873d commit 2568b96

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* Class generates all subsequences for a given list of elements using backtracking
8+
*/
9+
public final class SubsequenceFinder {
10+
private SubsequenceFinder() {
11+
}
12+
13+
/**
14+
* Find all subsequences of given list using backtracking
15+
*
16+
* @param sequence a list of items on the basis of which we need to generate all subsequences
17+
* @param <T> the type of elements in the array
18+
* @return a list of all subsequences
19+
*/
20+
public static <T> List<List<T>> generateAll(List<T> sequence) {
21+
List<List<T>> allSubSequences = new ArrayList<>();
22+
if (sequence.isEmpty()) {
23+
allSubSequences.add(new ArrayList<>());
24+
return allSubSequences;
25+
}
26+
List<T> currentSubsequence = new ArrayList<>();
27+
backtrack(sequence, currentSubsequence, 0, allSubSequences);
28+
return allSubSequences;
29+
}
30+
31+
/**
32+
* Iterate through each branch of states
33+
* We know that each state has exactly two branching
34+
* It terminates when it reaches the end of the given sequence
35+
*
36+
* @param sequence all elements
37+
* @param currentSubsequence current subsequence
38+
* @param index current index
39+
* @param allSubSequences contains all sequences
40+
* @param <T> the type of elements which we generate
41+
*/
42+
private static <T> void backtrack(List<T> sequence, List<T> currentSubsequence, final int index, List<List<T>> allSubSequences) {
43+
assert index <= sequence.size();
44+
if (index == sequence.size()) {
45+
allSubSequences.add(new ArrayList<>(currentSubsequence));
46+
return;
47+
}
48+
49+
backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
50+
currentSubsequence.add(sequence.get(index));
51+
backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
52+
currentSubsequence.removeLast();
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.thealgorithms.backtracking;
2+
3+
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.stream.Stream;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.MethodSource;
10+
11+
public class SubsequenceFinderTest {
12+
13+
@ParameterizedTest
14+
@MethodSource("getTestCases")
15+
void testGenerateAll(TestCase testData) {
16+
final var actual = SubsequenceFinder.generateAll(testData.input());
17+
assertIterableEquals(testData.expected(), actual);
18+
}
19+
20+
static Stream<TestCase> getTestCases() {
21+
return Stream.of(new TestCase(new ArrayList<>(), List.of(List.of())), new TestCase(List.of(1, 2), List.of(List.of(), List.of(2), List.of(1), List.of(1, 2))),
22+
new TestCase(List.of("A", "B", "C"), List.of(List.of(), List.of("C"), List.of("B"), List.of("B", "C"), List.of("A"), List.of("A", "C"), List.of("A", "B"), List.of("A", "B", "C"))),
23+
new TestCase(List.of(1, 2, 3), List.of(List.of(), List.of(3), List.of(2), List.of(2, 3), List.of(1), List.of(1, 3), List.of(1, 2), List.of(1, 2, 3))), new TestCase(List.of(2, 2), List.of(List.of(), List.of(2), List.of(2), List.of(2, 2))));
24+
}
25+
26+
record TestCase(List<Object> input, List<List<Object>> expected) {
27+
}
28+
}

0 commit comments

Comments
 (0)