diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarray.java b/src/main/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarray.java new file mode 100644 index 000000000000..1c16f612e98f --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarray.java @@ -0,0 +1,58 @@ +package com.thealgorithms.dynamicprogramming; + +/** + * The MaximumProductSubarray class implements the algorithm to find the + * maximum product of a contiguous subarray within a given array of integers. + * + *
Given an array of integers (which may contain positive numbers, negative + * numbers, and zeros), this algorithm finds the contiguous subarray that has + * the largest product. The algorithm handles negative numbers efficiently by + * tracking both maximum and minimum products, since a negative number can turn + * a minimum product into a maximum product.
+ * + *This implementation uses a dynamic programming approach that runs in O(n) + * time complexity and O(1) space complexity, making it highly efficient for + * large arrays.
+ */ +public final class MaximumProductSubarray { + + private MaximumProductSubarray() { + // Prevent instantiation + } + + /** + * Finds the maximum product of any contiguous subarray in the given array. + * + * @param nums an array of integers which may contain positive, negative, + * and zero values. + * @return the maximum product of a contiguous subarray. Returns 0 if the + * array is null or empty. + */ + public static int maxProduct(int[] nums) { + if (nums == null || nums.length == 0) { + return 0; + } + + long maxProduct = nums[0]; + long currentMax = nums[0]; + long currentMin = nums[0]; + + for (int i = 1; i < nums.length; i++) { + // Swap currentMax and currentMin if current number is negative + if (nums[i] < 0) { + long temp = currentMax; + currentMax = currentMin; + currentMin = temp; + } + + // Update currentMax and currentMin + currentMax = Math.max(nums[i], currentMax * nums[i]); + currentMin = Math.min(nums[i], currentMin * nums[i]); + + // Update global max product + maxProduct = Math.max(maxProduct, currentMax); + } + + return (int) maxProduct; + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarrayTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarrayTest.java new file mode 100644 index 000000000000..0f499bf2a2f7 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/MaximumProductSubarrayTest.java @@ -0,0 +1,152 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class MaximumProductSubarrayTest { + + /** + * Test case for an array with all positive numbers. + * The expected maximum product is the product of all elements. + */ + @Test + void testAllPositiveNumbers() { + int[] nums = {2, 3, 4}; + int expected = 24; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 24."); + } + + /** + * Test case for an array with positive and negative numbers. + * The expected maximum product is 24 (subarray [2, -3, -4]). + */ + @Test + void testMixedPositiveAndNegative() { + int[] nums = {2, -3, -4, 1}; + int expected = 24; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 24."); + } + + /** + * Test case for an array containing zeros. + * The expected maximum product is 24 (subarray [4, 6]). + */ + @Test + void testArrayWithZeros() { + int[] nums = {2, 3, 0, 4, 6}; + int expected = 24; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 24."); + } + + /** + * Test case for an array with a single element. + * The expected maximum product is the element itself. + */ + @Test + void testSingleElement() { + int[] nums = {5}; + int expected = 5; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 5."); + } + + /** + * Test case for an array with all negative numbers. + * The expected maximum product is 12 (subarray [-3, -4]). + */ + @Test + void testAllNegativeNumbers() { + int[] nums = {-2, -3, -4}; + int expected = 12; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 12."); + } + + /** + * Test case for an array with negative numbers where odd count of negatives + * breaks the chain. The expected maximum product is 60 (subarray [-2, -3, 10]). + */ + @Test + void testOddNegativeNumbers() { + int[] nums = {-2, -3, 10, -1}; + int expected = 60; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 60."); + } + + /** + * Test case for an empty array. + * The expected maximum product is 0. + */ + @Test + void testEmptyArray() { + int[] nums = {}; + int expected = 0; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 0 for an empty array."); + } + + /** + * Test case for a null array. + * The expected maximum product is 0. + */ + @Test + void testNullArray() { + int[] nums = null; + int expected = 0; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 0 for a null array."); + } + + /** + * Test case for an array with alternating positive and negative numbers. + * The expected maximum product is 6 (subarray [2, 3]). + */ + @Test + void testAlternatingNumbers() { + int[] nums = {2, 3, -2, 4}; + int expected = 6; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 6."); + } + + /** + * Test case for an array with large positive and negative numbers. + * The expected maximum product is 360 (subarray [6, -3, -20]). + */ + @Test + void testLargeNumbers() { + int[] nums = {6, -3, -20, 0, 5}; + int expected = 360; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 360."); + } + + /** + * Test case for an array with single negative number. + * The expected maximum product is the negative number itself. + */ + @Test + void testSingleNegativeElement() { + int[] nums = {-8}; + int expected = -8; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be -8."); + } + + /** + * Test case for an array with multiple zeros. + * The expected maximum product is 6 (subarray [2, 3]). + */ + @Test + void testMultipleZeros() { + int[] nums = {0, 2, 3, 0, 4}; + int expected = 6; + int actual = MaximumProductSubarray.maxProduct(nums); + assertEquals(expected, actual, "The maximum product should be 6."); + } +}