Skip to content

refactor: clean up LargestRectangle and convert tests to parameterized format #6356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 32 additions & 18 deletions src/main/java/com/thealgorithms/stacks/LargestRectangle.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
* <p>This implementation uses a monotonic stack to efficiently calculate
* the area of the largest rectangle that can be formed from the histogram bars.</p>
*
* <p>Example usage:
* <pre>{@code
* int[] heights = {2, 1, 5, 6, 2, 3};
* String area = LargestRectangle.largestRectangleHistogram(heights);
* // area is "10"
* }</pre>
*/

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<int[]> st = new Stack<>();
for (int i = 0; i < n; i++) {
Stack<int[]> 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);
}
}
79 changes: 15 additions & 64 deletions src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Arguments> 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;
}
}
Loading