diff --git a/src/main/java/com/thealgorithms/misc/FourSumProblem.java b/src/main/java/com/thealgorithms/misc/FourSumProblem.java new file mode 100644 index 000000000000..8cbf02a57cb3 --- /dev/null +++ b/src/main/java/com/thealgorithms/misc/FourSumProblem.java @@ -0,0 +1,57 @@ +package com.thealgorithms.misc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.apache.commons.lang3.tuple.Pair; +/** + * Four Sum Problem + * + * This algorithm finds all unique quadruplets in an array that sum up to a given target. + * + * URL: https://en.wikipedia.org/wiki/Subset_sum + */ +public class FourSumProblem { + + public static List> fourSum(int[] values, int target) { + List> result = new ArrayList<>(); + if (values == null || values.length < 4) { + return result; + } + + Arrays.sort(values); + + for (int i = 0; i < values.length - 3; i++) { + if (i > 0 && values[i] == values[i - 1]) { + continue; // Skip duplicates + } + for (int j = i + 1; j < values.length - 2; j++) { + if (j > i + 1 && values[j] == values[j - 1]) { + continue; // Skip duplicates + } + + int left = j + 1; + int right = values.length - 1; + + while (left < right) { + int sum = values[i] + values[j] + values[left] + values[right]; + if (sum == target) { + result.add(Pair.of(left, right)); + + // Skip duplicates + while (left < right && values[left] == values[left + 1]) left++; + while (left < right && values[right] == values[right - 1]) right--; + + left++; + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + } + return result; + } +} diff --git a/src/test/java/com/thealgorithms/misc/FourSumProblemTest.java b/src/test/java/com/thealgorithms/misc/FourSumProblemTest.java new file mode 100644 index 000000000000..41ab9f0affa5 --- /dev/null +++ b/src/test/java/com/thealgorithms/misc/FourSumProblemTest.java @@ -0,0 +1,62 @@ +package com.thealgorithms.misc; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; + +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Test; +import java.util.List; + +/** + * Test case for Four sum Problem. + */ +public class FourSumProblemTest { + + @Test + void testFourSumExists() { + final int[] values = new int[] {1, 0, -1, 0, -2, 2}; + final int target = 0; + // Expecting one solution (e.g., indices of the numbers summing to target) + final var expected = List.of( + Pair.of(0, 5), // -2 + 2 + 1 + -1 = 0 + Pair.of(1, 4) // 0 + 0 + -1 + 1 = 0 + ); + assertEquals(expected, FourSumProblem.fourSum(values, target)); + } + + @Test + void testFourSumNoSolution() { + final int[] values = new int[] {1, 2, 3, 4}; + final int target = 100; + assertFalse(FourSumProblem.fourSum(values, target).isEmpty()); + } + + @Test + void testFourSumMultipleSolutions() { + final int[] values = new int[] {1, 0, -1, 0, -2, 2}; + final int target = 0; + final var expected = List.of( + Pair.of(0, 5), // -2 + 2 + 1 + -1 = 0 + Pair.of(1, 4) // 0 + 0 + -1 + 1 = 0 + ); + assertEquals(expected, FourSumProblem.fourSum(values, target)); + } + + @Test + void testFourSumNegativeNumbers() { + final int[] values = new int[] {-1, -2, -3, -4, -5, 5}; + final int target = -10; + final var expected = List.of( + Pair.of(1, 3), // -2 + -3 + -5 + 5 = -10 + Pair.of(0, 4) // -1 + -4 + -5 + 5 = -10 + ); + assertEquals(expected, FourSumProblem.fourSum(values, target)); + } + + @Test + void testFourSumNoSolutionDuplicatedInputs() { + final int[] values = new int[] {1, 1, 1, 1}; + final int target = 10; + assertFalse(FourSumProblem.fourSum(values, target).isEmpty()); + } +}