diff --git a/src/main/java/com/thealgorithms/stacks/LargestRectangle.java b/src/main/java/com/thealgorithms/stacks/LargestRectangle.java index 006e03632e63..eb222c8c488e 100644 --- a/src/main/java/com/thealgorithms/stacks/LargestRectangle.java +++ b/src/main/java/com/thealgorithms/stacks/LargestRectangle.java @@ -3,36 +3,50 @@ import java.util.Stack; /** + * Utility class to calculate the largest rectangle area in a histogram. + * Each bar's width is assumed to be 1 unit. * - * @author mohd rameez github.com/rameez471 + *

This implementation uses a monotonic stack to efficiently calculate + * the area of the largest rectangle that can be formed from the histogram bars.

+ * + *

Example usage: + *

{@code
+ *     int[] heights = {2, 1, 5, 6, 2, 3};
+ *     String area = LargestRectangle.largestRectangleHistogram(heights);
+ *     // area is "10"
+ * }
*/ - public final class LargestRectangle { + private LargestRectangle() { } + /** + * Calculates the largest rectangle area in the given histogram. + * + * @param heights an array of non-negative integers representing bar heights + * @return the largest rectangle area as a {@link String} + */ public static String largestRectangleHistogram(int[] heights) { - int n = heights.length; int maxArea = 0; - Stack st = new Stack<>(); - for (int i = 0; i < n; i++) { + Stack stack = new Stack<>(); + + for (int i = 0; i < heights.length; i++) { int start = i; - while (!st.isEmpty() && st.peek()[1] > heights[i]) { - int[] tmp = st.pop(); - maxArea = Math.max(maxArea, tmp[1] * (i - tmp[0])); - start = tmp[0]; + while (!stack.isEmpty() && stack.peek()[1] > heights[i]) { + int[] popped = stack.pop(); + maxArea = Math.max(maxArea, popped[1] * (i - popped[0])); + start = popped[0]; } - st.push(new int[] {start, heights[i]}); + stack.push(new int[] {start, heights[i]}); } - while (!st.isEmpty()) { - int[] tmp = st.pop(); - maxArea = Math.max(maxArea, tmp[1] * (n - tmp[0])); + + int totalLength = heights.length; + while (!stack.isEmpty()) { + int[] remaining = stack.pop(); + maxArea = Math.max(maxArea, remaining[1] * (totalLength - remaining[0])); } - return Integer.toString(maxArea); - } - public static void main(String[] args) { - assert largestRectangleHistogram(new int[] {2, 1, 5, 6, 2, 3}).equals("10"); - assert largestRectangleHistogram(new int[] {2, 4}).equals("4"); + return Integer.toString(maxArea); } } diff --git a/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java b/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java index a54372adda0e..fec5d371c106 100644 --- a/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java +++ b/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java @@ -2,76 +2,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -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 LargestRectangleTest { - @Test - void testLargestRectangleHistogramWithTypicalCases() { - // Typical case with mixed heights - int[] heights = {2, 1, 5, 6, 2, 3}; - String expected = "10"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Another typical case with increasing heights - heights = new int[] {2, 4}; - expected = "4"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Case with multiple bars of the same height - heights = new int[] {4, 4, 4, 4}; - expected = "16"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); + @ParameterizedTest(name = "Histogram: {0} → Expected area: {1}") + @MethodSource("histogramProvider") + void testLargestRectangleHistogram(int[] heights, String expected) { + assertEquals(expected, LargestRectangle.largestRectangleHistogram(heights)); } - @Test - void testLargestRectangleHistogramWithEdgeCases() { - // Edge case with an empty array - int[] heights = {}; - String expected = "0"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Edge case with a single bar - heights = new int[] {5}; - expected = "5"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Edge case with all bars of height 0 - heights = new int[] {0, 0, 0}; - expected = "0"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); + static Stream histogramProvider() { + return Stream.of(Arguments.of(new int[] {2, 1, 5, 6, 2, 3}, "10"), Arguments.of(new int[] {2, 4}, "4"), Arguments.of(new int[] {4, 4, 4, 4}, "16"), Arguments.of(new int[] {}, "0"), Arguments.of(new int[] {5}, "5"), Arguments.of(new int[] {0, 0, 0}, "0"), + Arguments.of(new int[] {6, 2, 5, 4, 5, 1, 6}, "12"), Arguments.of(new int[] {2, 1, 5, 6, 2, 3, 1}, "10"), Arguments.of(createLargeArray(10000, 1), "10000")); } - @Test - void testLargestRectangleHistogramWithLargeInput() { - // Large input case - int[] heights = new int[10000]; - for (int i = 0; i < heights.length; i++) { - heights[i] = 1; - } - String expected = "10000"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - } - - @Test - void testLargestRectangleHistogramWithComplexCases() { - // Complex case with a mix of heights - int[] heights = {6, 2, 5, 4, 5, 1, 6}; - String expected = "12"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Case with a peak in the middle - heights = new int[] {2, 1, 5, 6, 2, 3, 1}; - expected = "10"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); + private static int[] createLargeArray(int size, int value) { + int[] arr = new int[size]; + java.util.Arrays.fill(arr, value); + return arr; } }