[单调栈入门] 496. 下一个更大元素 I

182 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

每日刷题 2022.06.01

题目

  • 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
  • nums1nums2中所有整数 互不相同
  • nums1 中的所有整数同样出现在 nums2

解题思路

  • 暴力的思路非常简单,就不多解释了。着重讲解下单调栈的解法,初次学习还请大家多多指教。
  • 首先题目中包含寻找下一个更大元素(Next Greater Number)这种字眼的话,题目一般考察的都是单调栈
  • 在考虑如何使用单调栈解决问题之前,先来思考下为什么要使用单调栈?

生活中的举例

  • 可以将整个数组想像成是几个高矮不同的学生。那么对于第i个高度的学生,想要找到其后面(右边)第一个高于他的学生。那么他只需要放眼往后看,可以看到的第一个人就是他后面第一个高于他的学生。(其中比当前学生个子矮的学生会被其他高的挡住看不到)
  • 根据图中所画可知,当你高度为3的时候,下一个更大的元素是其后面的下下一个位置的4,直接跳过了1。因为身高为3的学生,放眼往后望去并不能看到高度为1的学生。
  • 也就是说对于当前位置i,其后面比其矮的学生,都不会对最终的答案造成影响,因为答案不可能是他们。那么我们就可以使用单调栈,维护一个单调栈,来存储当前i的下一个更大值。 image.png

解题(原创图)

  • 具体的步骤(如下图所示,假设nums2 = [1,6,2,3,5,7]image.png image.png image.png image.png image.png image.png
  • 依靠于nums2数组中不存在重复的数字,因此对于nums2中的每一个元素求解其右边下一个更大的元素后,只需要再遍历一遍nums1,将每个值对应的下一个更大元素填入数组中即可。

AC代码

var nextGreaterElement = function(nums1, nums2) {
  // [4,1,2] 最后使用map来查找对应的值
  // [5,1,3,4,2] 先处理这个问题
  //  -1,3,4,-1,-1
  // stack: [5]
  // 时刻维护一个单调栈,一般都是单调递增,但是这里的单调递增并不是完全定以上的单调递增
  let s = [], m = new Map();
  const n1 = nums1.length, n2 = nums2.length;
  for(let i = n2 - 1; i >= 0; i--) {
    // 逆序遍历,找到右边的下一个更大元素
    // 不满足的时候,需要进行循环遍历
    let cur = nums2[i];
    while(!(s.length == 0) && cur >= s[s.length - 1]) {
      // 循环遍历
      s.pop();
    }
    // 循环寻找完成后,可能满足 也有可能不满足
    let res = s.length == 0 ? -1 : s[s.length - 1];
    s.push(cur);
    m.set(cur, res);
  }
  let ans = [];
  // 最后将nums1中对应的数值的下一个更大值填入到ans数组中
  for(let i = 0; i < n1; i++) {
    ans[i] = m.get(nums1[i]);
  }
  return ans;
};

总结

  • 单调栈主要用于寻找下一个更大元素(Next Greater Number)