class Solution:
def nextGreaterElement(self, nums1, nums2):
stack = []
next_greater = {}
for num in nums2:
while stack and num > stack[-1]:
prev = stack.pop()
next_greater[prev] = num
stack.append(num)
while stack:
next_greater[stack.pop()] = -1
return [next_greater[num] for num in nums1]
class Solution {
public:
vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
unordered_map<int, int> next_greater;
stack<int> st;
for (int num : nums2) {
while (!st.empty() && num > st.top()) {
next_greater[st.top()] = num;
st.pop();
}
st.push(num);
}
while (!st.empty()) {
next_greater[st.top()] = -1;
st.pop();
}
vector<int> res;
for (int num : nums1) {
res.push_back(next_greater[num]);
}
return res;
}
};
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Map<Integer, Integer> nextGreater = new HashMap<>();
Stack<Integer> stack = new Stack<>();
for (int num : nums2) {
while (!stack.isEmpty() && num > stack.peek()) {
nextGreater.put(stack.pop(), num);
}
stack.push(num);
}
while (!stack.isEmpty()) {
nextGreater.put(stack.pop(), -1);
}
int[] res = new int[nums1.length];
for (int i = 0; i < nums1.length; i++) {
res[i] = nextGreater.get(nums1[i]);
}
return res;
}
}
var nextGreaterElement = function(nums1, nums2) {
let stack = [];
let nextGreater = {};
for (let num of nums2) {
while (stack.length && num > stack[stack.length - 1]) {
nextGreater[stack.pop()] = num;
}
stack.push(num);
}
while (stack.length) {
nextGreater[stack.pop()] = -1;
}
return nums1.map(num => nextGreater[num]);
};
Given two integer arrays nums1
and nums2
, where nums1
is a subset of nums2
, the task is to find the "next greater element" for each element in nums1
with respect to nums2
.
The "next greater element" for an element x
in nums2
is the first element to the right of x
in nums2
that is greater than x
. If there is no such element, the answer should be -1
.
Return an array of answers for each element in nums1
. Each input will have exactly one valid answer, and you must not reuse elements from nums2
for multiple queries.
At first glance, you might think to simply, for each element in nums1
, search for its position in nums2
and then scan to the right to find the next greater element. This would work, but it would be inefficient, especially if the arrays are large.
To optimize, consider that the "next greater element" problem is a classic use case for a stack. By pre-processing nums2
and storing the next greater element for every number, we can answer each query in nums1
instantly. This is a shift from repeated searching to a one-time scan and constant-time lookups.
Think of it like preparing a cheat sheet: once you have the answer for every possible number in nums2
, you can answer any question about nums1
instantly.
nums2
from left to right.
nums2
:
-1
.
nums1
, look up its next greater element from the hash map and collect the answers.
The stack ensures that every number is processed just once, and the hash map allows for instant lookups, making the solution efficient.
Let's use the example: nums1 = [4,1,2]
, nums2 = [1,3,4,2]
nums2
:
1
: stack is empty, push 1
.3
: 3 > 1
, so 3
is next greater for 1
. Pop 1
, map 1 → 3
. Push 3
.4
: 4 > 3
, so 4
is next greater for 3
. Pop 3
, map 3 → 4
. Push 4
.2
: 2 < 4
, so just push 2
.4, 2
. They have no next greater, so map 4 → -1
and 2 → -1
.
nums1
:
4
: mapped to -1
1
: mapped to 3
2
: mapped to -1
[-1, 3, -1]
nums1
, you may scan almost all of nums2
to the right, leading to O(m * n)
time, where m
is length of nums1
and n
is length of nums2
.
nums2
once (O(n)
) and build a hash map. Then we build the answer for nums1
in O(m)
. Thus, total time is O(m + n)
.
O(n)
space in the worst case.
The optimized approach is much more efficient and scalable for large inputs.
By leveraging a stack and a hash map, we efficiently solve the Next Greater Element I problem in linear time. The key insight is to preprocess nums2
so that every query about nums1
can be answered instantly. This approach avoids repeated scans and makes the solution both elegant and practical for large datasets.