diff --git a/DIRECTORY.md b/DIRECTORY.md index 7bc9cea37..9ebbd4843 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -275,6 +275,7 @@ * [TilingProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/TilingProblem.java) * dynamicprogramming * [Abbreviation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Abbreviation.java) + * [AllConstruct](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java) * [AssignmentUsingBitmask](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmask.java) * [BoardPath](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BoardPath.java) * [BoundaryFill](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java) @@ -930,6 +931,7 @@ * [TilingProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/TilingProblemTest.java) * dynamicprogramming * [AbbreviationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/AbbreviationTest.java) + * [AllConstructTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java) * [AssignmentUsingBitmaskTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmaskTest.java) * [BoardPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java) * [BoundaryFillTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java) diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java b/src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java new file mode 100644 index 000000000..e7712b13a --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java @@ -0,0 +1,61 @@ +package com.thealgorithms.dynamicprogramming; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class provides a solution to the "All Construct" problem. + * + * The problem is to determine all the ways a target string can be constructed + * from a given list of substrings. Each substring in the word bank can be used + * multiple times, and the order of substrings matters. + * + * @author Hardvan + */ +public final class AllConstruct { + private AllConstruct() { + } + + /** + * Finds all possible ways to construct the target string using substrings + * from the given word bank. + * Time Complexity: O(n * m * k), where n = length of the target, + * m = number of words in wordBank, and k = average length of a word. + * + * Space Complexity: O(n * m) due to the size of the table storing combinations. + * + * @param target The target string to construct. + * @param wordBank An iterable collection of substrings that can be used to construct the target. + * @return A list of lists, where each inner list represents one possible + * way of constructing the target string using the given word bank. + */ + public static List> allConstruct(String target, Iterable wordBank) { + List>> table = new ArrayList<>(target.length() + 1); + + for (int i = 0; i <= target.length(); i++) { + table.add(new ArrayList<>()); + } + + table.get(0).add(new ArrayList<>()); + + for (int i = 0; i <= target.length(); i++) { + if (!table.get(i).isEmpty()) { + for (String word : wordBank) { + if (i + word.length() <= target.length() && target.substring(i, i + word.length()).equals(word)) { + + List> newCombinations = new ArrayList<>(); + for (List combination : table.get(i)) { + List newCombination = new ArrayList<>(combination); + newCombination.add(word); + newCombinations.add(newCombination); + } + + table.get(i + word.length()).addAll(newCombinations); + } + } + } + } + + return table.get(target.length()); + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java new file mode 100644 index 000000000..4979327fb --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java @@ -0,0 +1,38 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class AllConstructTest { + + @Test + public void testAllConstructBasic() { + List> expected = Arrays.asList(Arrays.asList("he", "l", "l", "o")); + List> result = AllConstruct.allConstruct("hello", Arrays.asList("he", "l", "o")); + assertEquals(expected, result); + } + + @Test + public void testAllConstructMultipleWays() { + List> expected = Arrays.asList(Arrays.asList("purp", "le"), Arrays.asList("p", "ur", "p", "le")); + List> result = AllConstruct.allConstruct("purple", Arrays.asList("purp", "p", "ur", "le", "purpl")); + assertEquals(expected, result); + } + + @Test + public void testAllConstructNoWays() { + List> expected = Arrays.asList(); + List> result = AllConstruct.allConstruct("abcdef", Arrays.asList("gh", "ijk")); + assertEquals(expected, result); + } + + @Test + public void testAllConstructEmptyTarget() { + List> expected = Arrays.asList(Arrays.asList()); + List> result = AllConstruct.allConstruct("", Arrays.asList("a", "b", "c")); + assertEquals(expected, result); + } +}