Skip to content

496. Next Greater Element

from typing import List


class Solution:
    """Find the next greater element for each element in nums1 using nums2.

    Problem Description:
    You are given two arrays `nums1` and `nums2`, where `nums1` is a subset of `nums2`.
    For each element in `nums1`, the goal is to find the next greater element in `nums2`.
    The next greater element for a number x in `nums2` is the first element to the right
    of x that is larger than x. If no such element exists, return -1.

    Approach:
    - To solve this problem efficiently, we use a stack and a dictionary to keep track of
      the next greater element for each number in `nums2`. Instead of iterating over
      `nums2` multiple times (O(n^2)), we process `nums2` in one pass.

    Solution Breakdown:
    1. We scan `nums2` from right to left. This ensures that when processing an element,
       all the potential next greater elements to its right have already been processed
       and are available for comparison.

    2. We use a stack to maintain a decreasing sequence of elements from `nums2`. As we
       move through the array, we pop elements from the stack that are smaller than the
       current element, because they cannot be the next greater element for any element
       to the left.

    3. The top of the stack after the popping process will be the next greater element
       for the current element in `nums2`. If the stack is empty, there is no greater
       element to the right, so we store `-1`.

    4. For fast lookup, we store the next greater element for each number in a dictionary
       (`next_greater`), where the key is the number and the value is its next greater
       element.

    5. Finally, for each element in `nums1`, we simply look up the precomputed next
       greater element in the `next_greater` dictionary and return the result.

    Time Complexity:
    - Processing `nums2` takes O(n), where n is the length of `nums2`. For each element,
      we perform a constant number of operations (push and pop), so stack operations are
      O(n).
    - Constructing the result for `nums1` takes O(m), where m is the length of `nums1`.
    - Total time complexity: O(n + m).

    Space Complexity:
    - We use a dictionary to store the next greater element for each element in `nums2`,
      which takes O(n) space.
    - The stack can also take up to O(n) space in the worst case.
    """

    def nextGreaterElement(self, nums1: List[int], nums2: List[int]) -> List[int]:
        # Use a dict to keep the next greater for each element in nums2
        next_greater = {}

        # Use a stack to keep the number, scanning nums2 in reverse order
        stack = []
        for num in reversed(nums2):
            # pop elements from the stack until the top is greater than num
            while stack and stack[-1] < num:
                stack.pop()
            # Get the next greater from the top of the stack
            next_greater[num] = stack[-1] if stack else -1

            # Push the current element on the stack
            stack.append(num)

        # Return the result for nums1 by looking up in the next_greater dictionary
        return [next_greater[num] for num in nums1]