Solution: Next Greater Element I

Let's solve the Next Greater Element I problem using the Hash Map pattern.

Statement

Given the two distinct integer arrays, nums1 and nums2, where nums1 is a subset of nums2, find all the next greater elements for nums1 values in the corresponding places of nums2.

In general, the next greater element of an element, xx, in an array is the first greater element present on the right side of xx in the same array. However, in the context of this problem, for each element xx in nums1, find the next greater element present on the right side of xx in nums2 and store it in the ans array. If there is no such element, store 1-1 for this number. The ans array should be of the same length as nums1, and the order of the elements in the ans array should correspond to the order of the elements in nums1.

Return the ans array after finding the next greater elements.

Note: The input data may or may not be sorted.

Constraints:

  • 11 \leq nums1.length \leq nums2.length 103\leq 10^3
  • 00 \leq nums1[i], nums2[i] 104\leq 10^4
  • nums1 have distinct integers.
  • nums2 have distinct integers.
  • All integers in nums1 also appear in nums2.

Solution

You’ve probably brainstormed some approaches and have an idea of how to solve this problem. Let’s explore some of these approaches and figure out which one to follow based on considerations such as time complexity and implementation constraints.

Naive approach

The naive approach is to select each element of nums1 and search for its occurrence in nums2. If the element is found, we look for the occurrence of its next greater element in nums2 linearly. If the next greater element is obtained, we store it in the ans array in the corresponding place to the element in nums1. Otherwise, we store 1-1 in the ans array for that element.

The overall time complexity of the algorithm becomes O(n1×n2)O(n_1 \times n_2), because we’re searching for each element of the nums1 array in the nums2 array. The space complexity of this algorithm is O(1)O(1).

Optimized solution using hash map

An optimized approach to solve this problem is using a hash map and a stack. A hash map is used to store the elements in nums2 as keys and their next greater elements as the respective values.

The algorithm proceeds through the following steps after creating an empty stack and a hash map:

  • Iterate over each element of nums2, and if the stack is not empty, compare it with the top element of the stack.

    • If the current element of nums2 is greater than the top element of the stack, pop the top element from the stack and put a key-value pair in the hash map with the popped element as the key and the current element of nums2 as the value.

    • This process uses a monotonic stackA monotonic stack maintains elements in either increasing or decreasing order, allowing efficient retrieval of the next greater or smaller elements in a sequence. that maintains elements in decreasing order, ensuring that the top of the stack always has the smallest element yet to find its next greater element. This allows efficient resolution of next greater elements.

    • Repeat the step above until either the stack becomes empty or the current element of nums2 is not greater than the top element of the stack.

  • After each iteration over nums2, push the current element of nums2 onto the stack.

  • After processing all the elements of nums2, check if any elements are still remaining in the stack. If they are, pop them and put key-value pairs in the hash map with the remaining elements as the keys and 1-1 as their respective values.

  • Finally, create an ans array with the same length as nums1 and populate it with the values from the hash map that correspond to the keys in nums1.

  • Return the ans array containing the next greater element for each element in nums1.

Let’s look at the following illustration to get a better understanding of the solution:

Press + to interact
canvasAnimation-image
1 of 17

Let’s implement the algorithm as discussed above:

class NextGreater {
public static int[] nextGreaterElement(int[] nums1, int[] nums2) {
Stack<Integer> stack = new Stack<>();
Map<Integer, Integer> map = new HashMap<>();
for (int current : nums2) {
while (!stack.empty() && current > stack.peek()) {
map.put(stack.pop(), current);
}
stack.push(current);
}
while (!stack.empty()) {
map.put(stack.pop(), -1);
}
int[] ans = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
ans[i] = map.get(nums1[i]);
}
return ans;
}
// Driver code
public static void main(String[] args) {
int[][] A = {
{2, 4},
{3, 2, 5},
{14, 45, 52},
{1, 3, 2},
{4, 2},
{0}
};
int[][] B = {
{1, 2, 3, 4},
{2, 3, 5, 1},
{52, 14, 45, 65},
{1, 3, 2, 4, 5},
{1, 2, 4, 3},
{0}
};
int x = 1;
for (int i = 0; i < A.length; i++) {
System.out.print(i + 1);
System.out.println(".\tNums 1 = " + Arrays.toString(A[i]));
System.out.println("\tNums 2 = " + Arrays.toString(B[i]));
System.out.print("");
System.out.println("\tThe Next Greater Element Array = " + Arrays.toString(nextGreaterElement(A[i], B[i])));
System.out.println(PrintHyphens.repeat("-", 100));
}
}
}
Next Greater Element I

Solution summary

  1. Create an empty stack and an empty hash map.

  2. Iterate over nums2, and for each element, compare it with the top element of the stack.

  3. If the current element of nums2 is greater than the top element, pop the top element and put a key-value pair in the hash map with the popped element as the key and the current element of nums2 as the value.

  4. Push the current element onto the stack.

  5. Repeat this process until we have iterated over all elements in nums2.

  6. Finally, iterate over nums1, and for each element, append its corresponding value from the hash map to a new array, ans.

  7. Return the ans array as the final result.

Time complexity

The for loop iterating over the elements of nums2 takes O(n)O(n) time, where nn is the length of nums2. Each stack’s nn element is pushed and popped exactly once, taking O(n)O(n) time. The for loop that populates the output array ans with values from the hash map takes O(m)O(m) time, where mm is the length of nums1.

So, the overall time complexity of the code is O(n+n+m)O(n + n + m). Since nums1 will always be a subset of nums2, mm will always be less than or equal to nn. Therefore, the time complexity can be simplified to O(n)O(n).

Space complexity

The stack can contain a maximum of nn elements, which is the length of nums2. The hash map can also contain a maximum of nn key-value pairs, one for each element in nums2. Therefore, the total space used by the stack and hash map is proportional to the length of nums2, resulting in a O(n)O(n) space complexity.

Level up your interview prep. Join Educative to access 70+ hands-on prep courses.