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..aabcb88ec3f7 --- /dev/null +++ b/src/main/java/com/thealgorithms/misc/FourSumProblem.java @@ -0,0 +1,64 @@ +package com.thealgorithms.misc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class FourSumProblem { + + /** + * The function "fourSumProblem" takes an array of integers and a target integer as input, and returns a list + * of unique quadruplets (four elements) from the array that sum up to the target value. + * It avoids duplicate quadruplets by sorting the array and skipping repeated numbers. + * The implementation uses a two-pointer approach to efficiently find the quadruplets. + * + * @param arr An array of integers. + * @param target The target sum that the four integers in each quadruplet should add up to. + * @return A list of lists, where each inner list contains four integers that sum up to the target value. + * @author saivardhan (https://github.com/saivardhan15) + */ + + public static List> fourSumProblem(int[] arr, int target) { + List> ans = new ArrayList<>(); + if (arr.length < 4) { + return ans; + } + // Sort the array to make it easier to detect duplicates + Arrays.sort(arr); + + // Loop over the first two elements + for (int i = 0; i < arr.length - 3; i++) { + if (i > 0 && arr[i] == arr[i - 1]) { // Skip duplicate numbers for 'i' + continue; + } + for (int j = i + 1; j < arr.length - 2; j++) { + if (j > i + 1 && arr[j] == arr[j - 1]) { // Skip duplicate numbers for 'j' + continue; + } + + // Two-pointer technique for the remaining two elements + int left = j + 1; + int right = arr.length - 1; + while (left < right) { + int sum = arr[i] + arr[j] + arr[left] + arr[right]; + if (sum == target) { + ans.add(Arrays.asList(arr[i], arr[j], arr[left], arr[right])); + while (left < right && arr[left] == arr[left + 1]) { // Skip duplicates for 'left' + left++; + } + while (left < right && arr[right] == arr[right - 1]) { // Skip duplicates for 'right' + right--; + } + left++; + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + } + return ans; + } +} 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..9e4328c06ca4 --- /dev/null +++ b/src/test/java/com/thealgorithms/misc/FourSumProblemTest.java @@ -0,0 +1,69 @@ +package com.thealgorithms.misc; +import git static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class FourSumProblemTest { + @Test + public void testEmptyArray() { + int[] arr = {}; + int target = 10; + List> result = FourSumProblem.fourSumProblem(arr, target); + assertTrue(result.isEmpty(), "Expected no quadruplets for an empty array"); + } + + @Test + public void testLessThanFourElements() { + int[] arr = {1, 2, 3}; + int target = 6; + List> result = FourSumProblem.fourSumProblem(arr, target); + assertTrue(result.isEmpty(), "Expected no quadruplets when array has less than 4 elements"); + } + + @Test + public void testNoValidQuadruplet() { + int[] arr = {1, 2, 3, 4, 5}; + int target = 100; + List> result = FourSumProblem.fourSumProblem(arr, target); + assertTrue(result.isEmpty(), "Expected no quadruplets when no combination matches the target"); + } + + @Test + public void testValidQuadruplet() { + int[] arr = {1, 0, -1, 0, -2, 2}; + int target = 0; + List> result = FourSumProblem.fourSumProblem(arr, target); + + List> expected = Arrays.asList(Arrays.asList(-2, -1, 1, 2), Arrays.asList(-2, 0, 0, 2), Arrays.asList(-1, 0, 0, 1)); + assertEquals(expected.size(), result.size(), "Expected 3 valid quadruplets"); + assertTrue(result.containsAll(expected), "The result should contain all expected quadruplets"); + } + + @Test + public void testWithDuplicates() { + int[] arr = {2, 2, 2, 2, 2}; + int target = 8; + List> result = FourSumProblem.fourSumProblem(arr, target); + + List> expected = Arrays.asList(Arrays.asList(2, 2, 2, 2)); + assertEquals(expected.size(), result.size(), "Expected 1 valid quadruplet for repeated numbers"); + assertTrue(result.containsAll(expected), "The result should contain the quadruplet [2, 2, 2, 2]"); + } + + @Test + public void testNegativeNumbers() { + int[] arr = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5}; + int target = 0; + List> result = FourSumProblem.fourSumProblem(arr, target); + + List> expected = Arrays.asList(Arrays.asList(-5, -4, 4, 5), Arrays.asList(-5, -3, 3, 5), Arrays.asList(-5, -2, 2, 5), Arrays.asList(-5, -2, 3, 4), Arrays.asList(-5, -1, 1, 5), Arrays.asList(-5, -1, 2, 4), Arrays.asList(-5, 0, 1, 4), Arrays.asList(-5, 0, 2, 3), + Arrays.asList(-4, -3, 2, 5), Arrays.asList(-4, -3, 3, 4), Arrays.asList(-4, -2, 1, 5), Arrays.asList(-4, -2, 2, 4), Arrays.asList(-4, -1, 0, 5), Arrays.asList(-4, -1, 1, 4), Arrays.asList(-4, -1, 2, 3), Arrays.asList(-4, 0, 1, 3), Arrays.asList(-3, -2, 0, 5), Arrays.asList(-3, -2, 1, 4), + Arrays.asList(-3, -2, 2, 3), Arrays.asList(-3, -1, 0, 4), Arrays.asList(-3, -1, 1, 3), Arrays.asList(-3, 0, 1, 2), Arrays.asList(-2, -1, 0, 3), Arrays.asList(-2, -1, 1, 2)); + + assertEquals(expected.size(), result.size(), "Expected 24 valid quadruplets for negative and positive numbers"); + assertTrue(result.containsAll(expected), "The result should contain all expected quadruplets"); + } +}