# [496] 下一个更大元素 I

nums1  中数字  x  的 下一个更大元素 是指  x  在  nums2 中对应位置 右侧 的 第一个 比  x  大的元素。

给你两个 没有重复元素 的数组  nums1 和  nums2 ,下标从 0 开始计数,其中 nums1  是  nums2  的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。

返回一个长度为  nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].

输出:[-1,3,-1]

解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。

  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

示例 2:

输入:nums1 = [2,4], nums2 = [1,2,3,4].

输出:[3,-1]

解释:nums1 中每个值的下一个更大元素如下所述:

  • 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。

  • 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。

提示:

1 <= nums1.length <= nums2.length <= 1000

0 <= nums1[i], nums2[i] <= 10^4

nums1 和 nums2 中所有整数 互不相同

nums1 中的所有整数同样出现在 nums2 中

进阶:你可以设计一个时间复杂度为 O(nums1.length + nums2.length) 的解决方案吗?

# 解析

这里需要引入一个新的知识点:单调栈算法

单调栈是用于计算这样一种情况:给你一个数字组成的数组,找到数组中每一个元素的下一个更大元素。

那么这样的问题该如何考虑呢?我们需要借助栈的结构。重点来了,这里我们需要首先将数组进行倒序遍历,从尾部开始形成单调栈结构。这样是为了我们在正序遍历时,可以从栈中正序出栈。

每次遍历时,判断并去除掉栈顶上小于等于当前数值的元素,由于栈顶元素较当前元素小,所以一定不是下一个更大元素。

之后,若此时的栈顶元素不为空,则当前栈顶元素为当前元素的下一个更大元素,否则返回 -1。

最后,将当前元素入栈,便于下一个元素遍历时比对。

因此,我们可以得出单调栈算法的代码实现:

// 单调栈算法,返回一个数组res,res[i] 表示 nums[i] 对应的下一个更大元素,如果后面没有更大的则返回-1。
function calculateGreaterElement(nums: number[]) {
  const len = nums.length;
  const res: number[] = [];
  // 单调栈,时刻维护栈是递增状态的
  const stack: number[] = [];

  // 倒序向单调栈中放入,是为了能正序出栈
  for (let i = len - 1; i >= 0; i--) {
    // 栈顶元素小于等于当前元素,则把栈中所有的小元素剔除掉,并在最后将当前元素入栈,从而保证栈的单调性
    while (stack.length > 0 && stack[stack.length - 1] <= nums[i]) {
      stack.pop();
    }

    // res[i] 表示 nums[i] 后面第一个更大的元素。
    // 此时的栈顶元素即为下一个更大元素
    // 如果栈空了就说明后面没有更大的了,返回 -1
    res[i] = stack.length === 0 ? -1 : stack[stack.length - 1];
    // 最后将当前元素入栈,从而保证栈的单调性
    stack.push(nums[i]);
  }

  return res;
}

在本题中,由于 nums1 是 nums2 的子集,因此,我们只需要计算出来 nums2 的下一个更大元素数组,然后为了加快查询效率,将 nums2 的每一个对应元素与其下一个更大元素做成映射。最终即可可以得出最终的题目结果。

function nextGreaterElement(nums1: number[], nums2: number[]): number[] {
  // 单调栈算法,返回一个数组res,res[i] 表示 nums[i] 对应的下一个更大元素,如果后面没有更大的则返回-1。
  const greater = calculateGreaterElement(nums2);

  // 生成 下一个更大元素的映射 map
  const greaterMap: Record<number, number> = {};
  for (let i = 0; i < nums2.length; i++) {
    greaterMap[nums2[i]] = greater[i];
  }

  const res: number[] = nums1.map(num => greaterMap[num]);
  return res;
}