From c848babd226e9a182608165c771be44ad145aecc Mon Sep 17 00:00:00 2001 From: yuvashreenarayanan3 <85839447+yuvashreenarayanan3@users.noreply.github.com> Date: Sun, 26 May 2024 17:20:32 +0000 Subject: [PATCH 1/4] Related to #5164 (Redesign of ArrayCombination) --- .../backtracking/ArrayCombination.java | 41 ++++++++---- .../backtracking/ArrayCombinationTest.java | 66 +++++++++---------- 2 files changed, 59 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java index a0b886e6be8a..c39e4048f8ad 100644 --- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java +++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java @@ -1,5 +1,6 @@ package com.thealgorithms.backtracking; +import java.util.ArrayList; import java.util.List; import java.util.TreeSet; @@ -8,25 +9,37 @@ * @author TheClerici (git-TheClerici) */ public final class ArrayCombination { - private 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. + * Find all combinations of 1..n using backtracking. + * + * @param n Max value of the elements. + * @param k Length of the combination. + * @return A list of all combinations of length k. + * Returns an empty list if k is 0 or n is less than k. */ - public static List> combination(int n, int k) { - if (n <= 0) { - return null; + public static List> combination(int n, int k) { + if (k <= 0 || n < k) { + return new ArrayList<>(); // Return empty list for invalid 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<>(), 1, 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); // Recursive call + current.remove(current.size() - 1); // 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 23fa5d54574c..e3bad572fac9 100644 --- a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java @@ -1,51 +1,49 @@ package com.thealgorithms.backtracking; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; +import java.util.ArrayList; import java.util.List; -import java.util.TreeSet; -import org.junit.jupiter.api.Test; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; public class ArrayCombinationTest { @Test - void testNBeingZeroOrLess() { - List> zeroResult = ArrayCombination.combination(0, 1); - List> negativeResult = ArrayCombination.combination(-1, 1); - assertNull(zeroResult); - assertNull(negativeResult); + public void testCombination() { + // Test case 1: n = 4, k = 2 + List> expected = new ArrayList<>(); + expected.add(List.of(1, 2)); + expected.add(List.of(1, 3)); + expected.add(List.of(1, 4)); + expected.add(List.of(2, 3)); + expected.add(List.of(2, 4)); + expected.add(List.of(3, 4)); + + List> actual = ArrayCombination.combination(4, 2); + + assertEquals(expected, actual); } @Test - void testNoLengthElement() { - List> result = ArrayCombination.combination(2, 0); - assertNull(result); - } + public void testEmptyCombination() { + // Test case 2: n = 4, k = 0 (invalid input) + List> expected = new ArrayList<>(); + List> actual = ArrayCombination.combination(4, 0); - @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()); + assertEquals(expected, actual); } @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]); - } + public void testSingleElementCombinations() { + // Test case 3: n = 3, k = 1 + List> expected = new ArrayList<>(); + expected.add(List.of(1)); + expected.add(List.of(2)); + expected.add(List.of(3)); - @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]); + List> actual = ArrayCombination.combination(3, 1); + + assertEquals(expected, actual); } -} +} \ No newline at end of file From 4b1d743770338f9423f8008f76f515162c3e23d6 Mon Sep 17 00:00:00 2001 From: yuvashreenarayanan3 <85839447+yuvashreenarayanan3@users.noreply.github.com> Date: Sun, 26 May 2024 17:35:11 +0000 Subject: [PATCH 2/4] Checkstyle fix --- .../com/thealgorithms/backtracking/ArrayCombination.java | 1 - .../com/thealgorithms/backtracking/ArrayCombinationTest.java | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java index c39e4048f8ad..17d4df5d06ef 100644 --- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java +++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.TreeSet; /** * Finds all permutations of 1...n of length k diff --git a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java index e3bad572fac9..f2005a74a7cd 100644 --- a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java @@ -1,10 +1,9 @@ package com.thealgorithms.backtracking; - import java.util.ArrayList; import java.util.List; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class ArrayCombinationTest { @@ -46,4 +45,4 @@ public void testSingleElementCombinations() { assertEquals(expected, actual); } -} \ No newline at end of file +} From a991febe9830e9082a117a07843777a5928936bb Mon Sep 17 00:00:00 2001 From: yuvashreenarayanan3 <85839447+yuvashreenarayanan3@users.noreply.github.com> Date: Sun, 26 May 2024 17:39:23 +0000 Subject: [PATCH 3/4] Clang_format --- .../java/com/thealgorithms/backtracking/ArrayCombination.java | 4 ++-- .../com/thealgorithms/backtracking/ArrayCombinationTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java index 17d4df5d06ef..22969cbcf55b 100644 --- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java +++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java @@ -8,7 +8,7 @@ * @author TheClerici (git-TheClerici) */ public final class ArrayCombination { - private ArrayCombination() { + private ArrayCombination() { } /** @@ -30,7 +30,7 @@ public static List> combination(int n, int k) { } private static void combine(List> combinations, List current, int start, int n, int k) { - if (current.size() == k) { // Base case: combination found + if (current.size() == k) { // Base case: combination found combinations.add(new ArrayList<>(current)); // Copy to avoid modification return; } diff --git a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java index f2005a74a7cd..8d78d6623276 100644 --- a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java @@ -1,10 +1,10 @@ package com.thealgorithms.backtracking; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.ArrayList; import java.util.List; - import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; public class ArrayCombinationTest { From 82aab4e19c49ebfafefd416c3071c2c1a8798e43 Mon Sep 17 00:00:00 2001 From: vil02 Date: Wed, 10 Jul 2024 19:11:18 +0200 Subject: [PATCH 4/4] refactor: cleanup --- .../backtracking/ArrayCombination.java | 20 ++++--- .../backtracking/ArrayCombinationTest.java | 54 ++++++++----------- 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java index 22969cbcf55b..a064decc0eb7 100644 --- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java +++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java @@ -4,28 +4,26 @@ import java.util.List; /** - * 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() { } /** - * Find all combinations of 1..n using backtracking. + * Finds all combinations of length k of 0..n-1 using backtracking. * - * @param n Max value of the elements. + * @param n Number of the elements. * @param k Length of the combination. * @return A list of all combinations of length k. - * Returns an empty list if k is 0 or n is less than k. */ public static List> combination(int n, int k) { - if (k <= 0 || n < k) { - return new ArrayList<>(); // Return empty list for invalid input + if (n < 0 || k < 0 || k > n) { + throw new IllegalArgumentException("Wrong input."); } List> combinations = new ArrayList<>(); - combine(combinations, new ArrayList<>(), 1, n, k); + combine(combinations, new ArrayList<>(), 0, n, k); return combinations; } @@ -35,10 +33,10 @@ private static void combine(List> combinations, List curr return; } - for (int i = start; i <= n; i++) { + for (int i = start; i < n; i++) { current.add(i); - combine(combinations, current, i + 1, n, k); // Recursive call - current.remove(current.size() - 1); // Backtrack + combine(combinations, current, i + 1, n, k); + current.removeLast(); // Backtrack } } } diff --git a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java index 8d78d6623276..a4ff7fe892d5 100644 --- a/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java +++ b/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java @@ -1,48 +1,36 @@ package com.thealgorithms.backtracking; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import com.thealgorithms.maths.BinomialCoefficient; import java.util.ArrayList; import java.util.List; -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 - public void testCombination() { - // Test case 1: n = 4, k = 2 - List> expected = new ArrayList<>(); - expected.add(List.of(1, 2)); - expected.add(List.of(1, 3)); - expected.add(List.of(1, 4)); - expected.add(List.of(2, 3)); - expected.add(List.of(2, 4)); - expected.add(List.of(3, 4)); - - List> actual = ArrayCombination.combination(4, 2); - - assertEquals(expected, actual); + @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 - public void testEmptyCombination() { - // Test case 2: n = 4, k = 0 (invalid input) - List> expected = new ArrayList<>(); - List> actual = ArrayCombination.combination(4, 0); - - assertEquals(expected, actual); + @ParameterizedTest + @MethodSource("wrongInputs") + void testCombinationThrows(int n, int k) { + assertThrows(IllegalArgumentException.class, () -> ArrayCombination.combination(n, k)); } - @Test - public void testSingleElementCombinations() { - // Test case 3: n = 3, k = 1 - List> expected = new ArrayList<>(); - expected.add(List.of(1)); - expected.add(List.of(2)); - expected.add(List.of(3)); - - List> actual = ArrayCombination.combination(3, 1); + 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)))); + } - assertEquals(expected, actual); + private static Stream wrongInputs() { + return Stream.of(Arguments.of(-1, 0), Arguments.of(0, -1), Arguments.of(2, 100)); } }