Skip to content

Commit c71585b

Browse files
Next Greater Element 1 with Monotonic Stack - Leetcode 496
1 parent 7a26aec commit c71585b

File tree

3 files changed

+208
-0
lines changed

3 files changed

+208
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package stack.next_greater_element_i;
2+
3+
import java.util.ArrayDeque;
4+
import java.util.Deque;
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
8+
/**
9+
* Solves the "Next Greater Element I" problem using a Monotonic Stack and a HashMap.
10+
*
11+
* <p>This approach is highly efficient because it avoids repeated searches. It works in
12+
* two main phases:
13+
* <ol>
14+
* <li><b>Pre-computation:</b> It iterates through the {@code nums2} array from right
15+
* to left, using a monotonic stack to find the next greater element for every
16+
* number in {@code nums2}. These results are stored in a map for instant retrieval.</li>
17+
* <li><b>Result Generation:</b> It then iterates through {@code nums1} and uses the
18+
* pre-computed map to look up the next greater element for each number, building
19+
* the final result array.</li>
20+
* </ol>
21+
*
22+
* <p><b>Complexity:</b>
23+
* <ul>
24+
* <li>Time: O(nums1.length + nums2.length), as each element in both arrays is
25+
* processed once.</li>
26+
* <li>Space: O(nums2.length) to store the map and the stack.</li>
27+
* </ul>
28+
*
29+
* @see <a href="https://leetcode.com/problems/next-greater-element-i/">LeetCode 496: Next Greater Element I</a>
30+
*/
31+
public class MonotonicStack {
32+
33+
/**
34+
* Finds the next greater element in {@code nums2} for each element in {@code nums1}.
35+
*
36+
* @param nums1 A subset of {@code nums2} for which to find the next greater elements.
37+
* @param nums2 The array in which to search for the next greater elements.
38+
* @return An array of the same length as {@code nums1}, where each element is the
39+
* next greater element, or -1 if none exists.
40+
*/
41+
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
42+
// Map to store {element -> nextGreaterElement} for nums2
43+
Map<Integer, Integer> nextGreaterMap = new HashMap<>();
44+
// Monotonic stack to keep track of elements in decreasing order
45+
Deque<Integer> stack = new ArrayDeque<>();
46+
47+
// 1. Pre-compute next greater elements for all numbers in nums2
48+
for (int i = nums2.length - 1; i >= 0; i--) {
49+
// Pop elements from the stack that are smaller than or equal to the current element
50+
while (!stack.isEmpty() && stack.peek() <= nums2[i]) {
51+
stack.pop();
52+
}
53+
54+
// The top of the stack is the next greater element. If stack is empty, there is none.
55+
nextGreaterMap.put(nums2[i], stack.isEmpty() ? -1 : stack.peek());
56+
57+
// Push the current element onto the stack for future comparisons
58+
stack.push(nums2[i]);
59+
}
60+
61+
// 2. Build the result array using the pre-computed map
62+
int[] result = new int[nums1.length];
63+
for (int i = 0; i < nums1.length; i++) {
64+
result[i] = nextGreaterMap.get(nums1[i]);
65+
}
66+
67+
return result;
68+
}
69+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Provides a solution for the "Next Greater Element I" problem.
3+
*
4+
* <p>The problem is defined as follows: Given two distinct integer arrays, {@code nums1} and
5+
* {@code nums2}, where {@code nums1} is a subset of {@code nums2}, find the next greater
6+
* element in {@code nums2} for each element in {@code nums1}. The "next greater element"
7+
* of a number {@code x} is the first number to its right in the same array that is
8+
* larger than {@code x}. If no such element exists, the answer is -1.
9+
*
10+
* <h3>Core Implementation Strategy</h3>
11+
*
12+
* <p>A naive approach of searching for each element of {@code nums1} in {@code nums2} and then
13+
* searching for its next greater element would be inefficient, leading to a complexity of
14+
* roughly O(N*M).
15+
*
16+
* <p>A much more optimal, two-pass approach is used here:
17+
* <ol>
18+
* <li><b>Pre-computation:</b> First, we process the larger array, {@code nums2}, to find the
19+
* next greater element for <em>every</em> number within it. This is efficiently
20+
* achieved using a <strong>Monotonic Stack</strong>. The results are stored in a
21+
* {@code HashMap} mapping each number to its next greater element.</li>
22+
* <li><b>Querying:</b> Second, we iterate through the smaller array, {@code nums1}. For each
23+
* number, we perform a quick O(1) lookup in the pre-computed map to find its
24+
* corresponding next greater element.</li>
25+
* </ol>
26+
*
27+
* <p>This strategy reduces the overall time complexity to O(nums1.length + nums2.length),
28+
* as each array is traversed only once.
29+
*
30+
* @version 1.0
31+
* @see <a href="https://leetcode.com/problems/next-greater-element-i/">LeetCode 496: Next Greater Element I</a>
32+
* @since 1.0
33+
*/
34+
package stack.next_greater_element_i;
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package stack.next_greater_element_i;
2+
3+
import org.junit.jupiter.api.DisplayName;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
7+
8+
/**
9+
* Test suite for the {@link MonotonicStack} class.
10+
*/
11+
class MonotonicStackTest {
12+
13+
private final MonotonicStack monotonicStack = new MonotonicStack();
14+
15+
@Test
16+
@DisplayName("Should pass the primary LeetCode example")
17+
void testLeetCodeExample1() {
18+
// Arrange
19+
int[] nums1 = {4, 1, 2};
20+
int[] nums2 = {1, 3, 4, 2};
21+
int[] expected = {-1, 3, -1};
22+
23+
// Act
24+
int[] result = monotonicStack.nextGreaterElement(nums1, nums2);
25+
26+
// Assert
27+
assertArrayEquals(expected, result, "Should find the correct next greater elements");
28+
}
29+
30+
@Test
31+
@DisplayName("Should pass the second LeetCode example")
32+
void testLeetCodeExample2() {
33+
// Arrange
34+
int[] nums1 = {2, 4};
35+
int[] nums2 = {1, 2, 3, 4};
36+
int[] expected = {3, -1};
37+
38+
// Act
39+
int[] result = monotonicStack.nextGreaterElement(nums1, nums2);
40+
41+
// Assert
42+
assertArrayEquals(expected, result, "Should handle cases where the element is at the end");
43+
}
44+
45+
@Test
46+
@DisplayName("Should return -1 for all elements when nums2 is strictly decreasing")
47+
void testStrictlyDecreasingArray() {
48+
// Arrange
49+
int[] nums1 = {5, 3, 1};
50+
int[] nums2 = {5, 4, 3, 2, 1};
51+
int[] expected = {-1, -1, -1};
52+
53+
// Act
54+
int[] result = monotonicStack.nextGreaterElement(nums1, nums2);
55+
56+
// Assert
57+
assertArrayEquals(expected, result, "All results should be -1 for a decreasing array");
58+
}
59+
60+
@Test
61+
@DisplayName("Should find the adjacent element when nums2 is strictly increasing")
62+
void testStrictlyIncreasingArray() {
63+
// Arrange
64+
int[] nums1 = {1, 2, 3, 4};
65+
int[] nums2 = {1, 2, 3, 4, 5};
66+
int[] expected = {2, 3, 4, 5};
67+
68+
// Act
69+
int[] result = monotonicStack.nextGreaterElement(nums1, nums2);
70+
71+
// Assert
72+
assertArrayEquals(expected, result, "Next greater element should be the next one in sequence");
73+
}
74+
75+
@Test
76+
@DisplayName("Should work correctly when nums1 is a permutation of nums2")
77+
void testWhenNums1IsPermutationOfNums2() {
78+
// Arrange
79+
int[] nums1 = {1, 3, 5, 2, 4};
80+
int[] nums2 = {1, 3, 5, 2, 4};
81+
int[] expected = {3, 5, -1, 4, -1};
82+
83+
// Act
84+
int[] result = monotonicStack.nextGreaterElement(nums1, nums2);
85+
86+
// Assert
87+
assertArrayEquals(expected, result, "Should handle the case where nums1 and nums2 are the same");
88+
}
89+
90+
@Test
91+
@DisplayName("Should handle a more complex, mixed scenario")
92+
void testComplexScenario() {
93+
// Arrange
94+
int[] nums1 = {13, 7, 6, 12};
95+
int[] nums2 = {1, 3, 7, 4, 6, 9, 13, 12, 11};
96+
// NGE map for nums2: {1:3, 3:7, 7:9, 4:6, 6:9, 9:13, 13:-1, 12:-1, 11:-1}
97+
int[] expected = {-1, 9, 9, -1};
98+
99+
// Act
100+
int[] result = monotonicStack.nextGreaterElement(nums1, nums2);
101+
102+
// Assert
103+
assertArrayEquals(expected, result, "Should correctly process a complex sequence");
104+
}
105+
}

0 commit comments

Comments
 (0)