From f83bb659ba54f0133040c0c4c1b74955c6e8e830 Mon Sep 17 00:00:00 2001 From: yuvashreenarayanan3 <85839447+yuvashreenarayanan3@users.noreply.github.com> Date: Wed, 10 Jul 2024 22:50:32 +0530 Subject: [PATCH] refactor: redesign `ArrayCombination` (#5181) * Related to #5164 (Redesign of ArrayCombination) * Checkstyle fix * Clang_format * refactor: cleanup --------- Co-authored-by: Piotr Idzik <65706193+vil02@users.noreply.github.com> Co-authored-by: vil02 --- .../backtracking/ArrayCombination.java | 42 ++++++++------ .../backtracking/ArrayCombinationTest.java | 57 +++++++------------ 2 files changed, 47 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java index a0b886e6..a064decc 100644 --- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java +++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java @@ -1,32 +1,42 @@ package com.thealgorithms.backtracking; +import java.util.ArrayList; import java.util.List; -import java.util.TreeSet; /** - * Finds all permutations of 1...n of length k - * @author TheClerici (git-TheClerici) + * Finds all combinations of 0...n-1 of length k */ public final class ArrayCombination { private ArrayCombination() { } - private static int length; /** - * Find all combinations of 1..n by creating an array and using backtracking in Combination.java - * @param n max value of the array. - * @param k length of combination - * @return a list of all combinations of length k. If k == 0, return null. + * Finds all combinations of length k of 0..n-1 using backtracking. + * + * @param n Number of the elements. + * @param k Length of the combination. + * @return A list of all combinations of length k. */ - public static List> combination(int n, int k) { - if (n <= 0) { - return null; + public static List> combination(int n, int k) { + if (n < 0 || k < 0 || k > n) { + throw new IllegalArgumentException("Wrong input."); } - length = k; - Integer[] arr = new Integer[n]; - for (int i = 1; i <= n; i++) { - arr[i - 1] = i; + + List> combinations = new ArrayList<>(); + combine(combinations, new ArrayList<>(), 0, n, k); + return combinations; + } + + private static void combine(List> combinations, List current, int start, int n, int k) { + if (current.size() == k) { // Base case: combination found + combinations.add(new ArrayList<>(current)); // Copy to avoid modification + return; + } + + for (int i = start; i < n; i++) { + current.add(i); + combine(combinations, current, i + 1, n, k); + current.removeLast(); // Backtrack } - return Combination.combination(arr, length); } } diff --git a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java index 23fa5d54..a4ff7fe8 100644 --- a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java @@ -1,51 +1,36 @@ package com.thealgorithms.backtracking; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import com.thealgorithms.maths.BinomialCoefficient; +import java.util.ArrayList; import java.util.List; -import java.util.TreeSet; -import org.junit.jupiter.api.Test; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class ArrayCombinationTest { - - @Test - void testNBeingZeroOrLess() { - List> zeroResult = ArrayCombination.combination(0, 1); - List> negativeResult = ArrayCombination.combination(-1, 1); - assertNull(zeroResult); - assertNull(negativeResult); + @ParameterizedTest + @MethodSource("regularInputs") + void testCombination(int n, int k, List> expected) { + assertEquals(expected.size(), BinomialCoefficient.binomialCoefficient(n, k)); + assertEquals(expected, ArrayCombination.combination(n, k)); } - @Test - void testNoLengthElement() { - List> result = ArrayCombination.combination(2, 0); - assertNull(result); + @ParameterizedTest + @MethodSource("wrongInputs") + void testCombinationThrows(int n, int k) { + assertThrows(IllegalArgumentException.class, () -> ArrayCombination.combination(n, k)); } - @Test - void testLengthOne() { - List> result = ArrayCombination.combination(2, 1); - assert result != null; - assertEquals(1, result.get(0).iterator().next()); - assertEquals(2, result.get(1).iterator().next()); + private static Stream regularInputs() { + return Stream.of(Arguments.of(0, 0, List.of(new ArrayList())), Arguments.of(1, 0, List.of(new ArrayList())), Arguments.of(1, 1, List.of(List.of(0))), Arguments.of(3, 0, List.of(new ArrayList())), Arguments.of(3, 1, List.of(List.of(0), List.of(1), List.of(2))), + Arguments.of(4, 2, List.of(List.of(0, 1), List.of(0, 2), List.of(0, 3), List.of(1, 2), List.of(1, 3), List.of(2, 3)))); } - @Test - void testLengthTwo() { - List> result = ArrayCombination.combination(2, 2); - assert result != null; - Integer[] arr = result.get(0).toArray(new Integer[2]); - assertEquals(1, arr[0]); - assertEquals(2, arr[1]); - } - - @Test - void testLengthFive() { - List> result = ArrayCombination.combination(10, 5); - assert result != null; - Integer[] arr = result.get(0).toArray(new Integer[5]); - assertEquals(1, arr[0]); - assertEquals(5, arr[4]); + private static Stream wrongInputs() { + return Stream.of(Arguments.of(-1, 0), Arguments.of(0, -1), Arguments.of(2, 100)); } }