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 <65706193+vil02@users.noreply.github.com>
This commit is contained in:
Alex K 2024-05-30 21:43:15 +03:00 committed by GitHub
parent a6e873deef
commit 2568b96784
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 82 additions and 0 deletions

View File

@ -0,0 +1,54 @@
package com.thealgorithms.backtracking;
import java.util.ArrayList;
import java.util.List;
/**
* Class generates all subsequences for a given list of elements using backtracking
*/
public final class SubsequenceFinder {
private SubsequenceFinder() {
}
/**
* Find all subsequences of given list using backtracking
*
* @param sequence a list of items on the basis of which we need to generate all subsequences
* @param <T> the type of elements in the array
* @return a list of all subsequences
*/
public static <T> List<List<T>> generateAll(List<T> sequence) {
List<List<T>> allSubSequences = new ArrayList<>();
if (sequence.isEmpty()) {
allSubSequences.add(new ArrayList<>());
return allSubSequences;
}
List<T> currentSubsequence = new ArrayList<>();
backtrack(sequence, currentSubsequence, 0, allSubSequences);
return allSubSequences;
}
/**
* Iterate through each branch of states
* We know that each state has exactly two branching
* It terminates when it reaches the end of the given sequence
*
* @param sequence all elements
* @param currentSubsequence current subsequence
* @param index current index
* @param allSubSequences contains all sequences
* @param <T> the type of elements which we generate
*/
private static <T> void backtrack(List<T> sequence, List<T> currentSubsequence, final int index, List<List<T>> allSubSequences) {
assert index <= sequence.size();
if (index == sequence.size()) {
allSubSequences.add(new ArrayList<>(currentSubsequence));
return;
}
backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
currentSubsequence.add(sequence.get(index));
backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
currentSubsequence.removeLast();
}
}

View File

@ -0,0 +1,28 @@
package com.thealgorithms.backtracking;
import static org.junit.jupiter.api.Assertions.assertIterableEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
public class SubsequenceFinderTest {
@ParameterizedTest
@MethodSource("getTestCases")
void testGenerateAll(TestCase testData) {
final var actual = SubsequenceFinder.generateAll(testData.input());
assertIterableEquals(testData.expected(), actual);
}
static Stream<TestCase> getTestCases() {
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))),
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"))),
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))));
}
record TestCase(List<Object> input, List<List<Object>> expected) {
}
}