Skip to content

Commit 68fef34

Browse files
committed
feat-Add MaximumProductSubarray
1 parent 4fe37c3 commit 68fef34

File tree

2 files changed

+245
-0
lines changed

2 files changed

+245
-0
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
/**
4+
* The MaximumProductSubarray class implements the algorithm to find the
5+
* maximum product of a contiguous subarray within a given array of integers.
6+
*
7+
* <p>Given an array of integers (which may contain positive numbers, negative
8+
* numbers, and zeros), this algorithm finds the contiguous subarray that has
9+
* the largest product. The algorithm handles negative numbers efficiently by
10+
* tracking both maximum and minimum products, since a negative number can turn
11+
* a minimum product into a maximum product.</p>
12+
*
13+
* <p>This implementation uses a dynamic programming approach that runs in O(n)
14+
* time complexity and O(1) space complexity, making it highly efficient for
15+
* large arrays.</p>
16+
*/
17+
public final class MaximumProductSubarray {
18+
private MaximumProductSubarray() {
19+
}
20+
21+
/**
22+
* Finds the maximum product of any contiguous subarray in the given array.
23+
*
24+
* @param nums an array of integers which may contain positive, negative,
25+
* and zero values.
26+
* @return the maximum product of a contiguous subarray. Returns 0 if the
27+
* array is empty.
28+
*/
29+
public static int maxProduct(int[] nums) {
30+
if (nums == null || nums.length == 0) {
31+
return 0;
32+
}
33+
34+
int maxProduct = nums[0];
35+
int currentMax = nums[0];
36+
int currentMin = nums[0];
37+
38+
for (int i = 1; i < nums.length; i++) {
39+
if (nums[i] < 0) {
40+
int temp = currentMax;
41+
currentMax = currentMin;
42+
currentMin = temp;
43+
}
44+
45+
currentMax = Math.max(nums[i], currentMax * nums[i]);
46+
currentMin = Math.min(nums[i], currentMin * nums[i]);
47+
48+
maxProduct = Math.max(maxProduct, currentMax);
49+
}
50+
51+
return maxProduct;
52+
}
53+
54+
/**
55+
* Finds the maximum product using a memoization approach with recursion.
56+
* This method explores all possible subarrays and stores intermediate results.
57+
*
58+
* @param nums an array of integers which may contain positive, negative,
59+
* and zero values.
60+
* @return the maximum product of a contiguous subarray. Returns 0 if the
61+
* array is empty.
62+
*/
63+
public static int maxProductMemoized(int[] nums) {
64+
if (nums == null || nums.length == 0) {
65+
return 0;
66+
}
67+
68+
int n = nums.length;
69+
Integer[][] memo = new Integer[n][n];
70+
int maxProduct = Integer.MIN_VALUE;
71+
72+
for (int i = 0; i < n; i++) {
73+
for (int j = i; j < n; j++) {
74+
maxProduct = Math.max(maxProduct, calculateProduct(nums, memo, i, j));
75+
}
76+
}
77+
78+
return maxProduct;
79+
}
80+
81+
/**
82+
* A recursive helper method to calculate the product of elements from index
83+
* start to index end using memoization.
84+
*
85+
* @param nums the input array of integers.
86+
* @param memo the memoization table storing the results of subproblems.
87+
* @param start the starting index of the subarray.
88+
* @param end the ending index of the subarray.
89+
* @return the product of elements from start to end.
90+
*/
91+
private static int calculateProduct(int[] nums, Integer[][] memo, int start, int end) {
92+
if (memo[start][end] != null) {
93+
return memo[start][end];
94+
}
95+
96+
if (start == end) {
97+
memo[start][end] = nums[start];
98+
return nums[start];
99+
}
100+
101+
int product = calculateProduct(nums, memo, start, end - 1) * nums[end];
102+
memo[start][end] = product;
103+
return product;
104+
}
105+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
package com.thealgorithms.dynamicprogramming;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
class MaximumProductSubarrayTest {
8+
9+
/**
10+
* Test case for an array with all positive numbers.
11+
* The expected maximum product is the product of all elements.
12+
*/
13+
@Test
14+
void testAllPositiveNumbers() {
15+
int[] nums = {2, 3, 4};
16+
int expected = 24;
17+
int actual = MaximumProductSubarray.maxProduct(nums);
18+
assertEquals(expected, actual, "The maximum product should be 24.");
19+
}
20+
21+
/**
22+
* Test case for an array with positive and negative numbers.
23+
* The expected maximum product is 24 (subarray [2, -3, -4]).
24+
*/
25+
@Test
26+
void testMixedPositiveAndNegative() {
27+
int[] nums = {2, -3, -4, 1};
28+
int expected = 24;
29+
int actual = MaximumProductSubarray.maxProduct(nums);
30+
assertEquals(expected, actual, "The maximum product should be 24.");
31+
}
32+
33+
/**
34+
* Test case for an array containing zeros.
35+
* The expected maximum product is 24 (subarray [2, 3, 4]).
36+
*/
37+
@Test
38+
void testArrayWithZeros() {
39+
int[] nums = {2, 3, 0, 4, 6};
40+
int expected = 24;
41+
int actual = MaximumProductSubarray.maxProduct(nums);
42+
assertEquals(expected, actual, "The maximum product should be 24.");
43+
}
44+
45+
/**
46+
* Test case for an array with a single element.
47+
* The expected maximum product is the element itself.
48+
*/
49+
@Test
50+
void testSingleElement() {
51+
int[] nums = {5};
52+
int expected = 5;
53+
int actual = MaximumProductSubarray.maxProduct(nums);
54+
assertEquals(expected, actual, "The maximum product should be 5.");
55+
}
56+
57+
/**
58+
* Test case for an array with all negative numbers.
59+
* The expected maximum product is the largest single negative number.
60+
*/
61+
@Test
62+
void testAllNegativeNumbers() {
63+
int[] nums = {-2, -3, -4};
64+
int expected = 12;
65+
int actual = MaximumProductSubarray.maxProduct(nums);
66+
assertEquals(expected, actual, "The maximum product should be 12.");
67+
}
68+
69+
/**
70+
* Test case for an array with negative numbers where odd count of negatives
71+
* breaks the chain. The expected maximum product is 60 (subarray [-2, -3, 10]).
72+
*/
73+
@Test
74+
void testOddNegativeNumbers() {
75+
int[] nums = {-2, -3, 10, -1};
76+
int expected = 60;
77+
int actual = MaximumProductSubarray.maxProduct(nums);
78+
assertEquals(expected, actual, "The maximum product should be 60.");
79+
}
80+
81+
/**
82+
* Test case for an empty array.
83+
* The expected maximum product is 0.
84+
*/
85+
@Test
86+
void testEmptyArray() {
87+
int[] nums = {};
88+
int expected = 0;
89+
int actual = MaximumProductSubarray.maxProduct(nums);
90+
assertEquals(expected, actual, "The maximum product should be 0 for an empty array.");
91+
}
92+
93+
/**
94+
* Test case for an array with alternating positive and negative numbers.
95+
* The expected maximum product is 6 (subarray [2, 3]).
96+
*/
97+
@Test
98+
void testAlternatingNumbers() {
99+
int[] nums = {2, 3, -2, 4};
100+
int expected = 6;
101+
int actual = MaximumProductSubarray.maxProduct(nums);
102+
assertEquals(expected, actual, "The maximum product should be 6.");
103+
}
104+
105+
/**
106+
* Test case for the memoized version with all positive numbers.
107+
* The expected maximum product is 24.
108+
*/
109+
@Test
110+
void testMemoizedAllPositiveNumbers() {
111+
int[] nums = {2, 3, 4};
112+
int expected = 24;
113+
int actual = MaximumProductSubarray.maxProductMemoized(nums);
114+
assertEquals(expected, actual, "The maximum product should be 24.");
115+
}
116+
117+
/**
118+
* Test case for the memoized version with mixed positive and negative numbers.
119+
* The expected maximum product is 24.
120+
*/
121+
@Test
122+
void testMemoizedMixedNumbers() {
123+
int[] nums = {2, -3, -4, 1};
124+
int expected = 24;
125+
int actual = MaximumProductSubarray.maxProductMemoized(nums);
126+
assertEquals(expected, actual, "The maximum product should be 24.");
127+
}
128+
129+
/**
130+
* Test case for an array with large positive and negative numbers.
131+
* The expected maximum product is 720 (subarray [6, -3, -20]).
132+
*/
133+
@Test
134+
void testLargeNumbers() {
135+
int[] nums = {6, -3, -20, 0, 5};
136+
int expected = 360;
137+
int actual = MaximumProductSubarray.maxProduct(nums);
138+
assertEquals(expected, actual, "The maximum product should be 360.");
139+
}
140+
}

0 commit comments

Comments
 (0)