JS Leetcode 496. 下一个更大元素 I 更清晰的图解单调栈做法

壹 ❀ 引
最近一周的工作压力很大...一周的时间一直在处理一个APP漏洞问题,因为项目三年无人维护,突然要改东西光是修改构建错误以及三方包依赖错误就花了三天时间= =。不过好在问题到已经结束尾,闲下来还是记录下最近的解题思路,本题来自LeetCode496. 下一个更大元素 I,难度属于简单,题目描述如下:
给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。
请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。
nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。
示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
对于 num1 中的数字 4 ,你无法在第二个数组中找到下一个更大的数字,因此输出 -1 。
对于 num1 中的数字 1 ,第二个数组中数字1右边的下一个较大数字是 3 。
对于 num1 中的数字 2 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
示例 2:
输入: nums1 = [2,4], nums2 = [1,2,3,4].
输出: [3,-1]
解释:
对于 num1 中的数字 2 ,第二个数组中的下一个较大数字是 3 。
对于 num1 中的数字 4 ,第二个数组中没有下一个更大的数字,因此输出 -1 。
提示:
1 <= nums1.length <= nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 104
nums1和nums2中所有整数 互不相同
nums1 中的所有整数同样出现在 nums2 中
贰 ❀ 暴力解法
简单提取下题目中的信息,首先数组nums1是数组nums2的子集,也就是子数组,且数组中不存在重复元素。题目要求是每次取nums1中的一个元素,去nums2中的与之相同的这个元素开始找,看看还有没有比它大的元素,如果有,记录这个元素,如果没有则记录为-1,最终返回包含这些结束的数组。
思路其实就很清晰了,我们可以先遍历nums1每次取一个元素,并查询此元素在nums2中的索引,那么nums2就可以从此索引+1的位置开始遍历,判断还有没有比num1[i]更大的元素,有就记录,无就记录-1即可。
大家可以先根据这个思路自己实现代码,毕竟还是有些细节需要自己感受,下面附上代码:
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var nextGreaterElement = function (nums1, nums2) {
let res = [];
// 遍历nums1,每次取一个出来
for (let i = 0; i < nums1.length; i++) {
// 查找nums1[i]在nums2中的位置
let index = nums2.indexOf(nums1[i]);
// 需要注意的是这个元素可能是nums2中的最后一个,如果是最后一个就无法满足nums2的遍历条件,因此直接加入-1
if (index === nums2.length - 1) {
res.push(-1);
};
// 从查找到的索引+1位开始查找,有记录更大元素,无则记录-1
for (let j = index + 1; j < nums2.length; j++) {
if (nums2[j] > nums1[i]) {
res.push(nums2[j]);
// 因为无重复元素,找到更大的就跳出循环
break;
} else if (j === nums2.length - 1) {
res.push(-1)
};
};
};
return res;
};
代码注释写的非常清楚,这里就不多解释了,我们接下来看看官方推荐的解题思路。
贰 ❀ 单调栈思路
当然,我在看单调栈题解之前,肯定是不知道这个思路以及做法的,这里的想法自然也是来自题解区的各位大佬。其中我在看到了LeetCode用户labuladong题解时觉得非常的形象也较好理解,这里借鉴下。
比如我们要求数组[2,1,2,4,3]中每个元素的下一个更大数,其实答案很明显是[4,2,4,-1,-1],要做到求出此结果,我们一样可以从当前元素往后遍历,一直遇到第一个比自己大的元素,若遍历完还没遇到就记录为-1级了。
其实有个很有趣的比喻就是,我们可以将数组中的每个元素理解为不同身高的人,然后每个人往后看,那么这个人的视线一定是被第一个比自己高的人给挡住,用图表示就是:

那么怎么用程序表示这个过程呢?这里就得借用单调栈了。我们都知道栈有FILO(先进后出)的特性。所谓单调栈,即是入栈时经过某种处理,让入栈后的元素满足单调递增或者单调递减的顺序,说直白点就是有序的栈。可能说到这还是比较模糊,我们直接针对[2,1,2,4,3]的例子给出一个代码,再去分析,我想这样会好理解一点,代码如下:
var nextGreaterElement = function (nums) {
let res = [];
let stack = [];
// 因为栈是先进后出,所以倒序遍历反而满足了正向使用
// 对应到比身高里面,我们都是往后看,那就从最后一个开始,一个接一个往后看,这也也便于知道谁是第一个比自己高的人
for (let i = nums.length - 1; i >= 0; i--) {
// 如果栈不为空,且栈顶第一个元素(对应到数组中最后一个元素)比当前nums[i]还矮就得弹出去
while (stack.length && stack[stack.length - 1] <= nums[i]) {
// 比nums[i]矮的人都弹出去
// 因为nums是倒序遍历,每个人都是往后看比身高,假设nums[i]比后面的人还高,那么nums[i]前面的人一定只能看到
// 自己,而看不到nums[i]后面的人,那么记录后面的人是没意义的,因为反正都会被nums[i]挡住,因此统统弹出去不记录。
stack.pop();
};
// 记录第i个比自己更高的人
// 因为上面的逻辑中,比nums[i]矮的人会被全部弹出栈,最坏的情况就是没有比自己高的,栈被清空了,因此为-1;
// 而如果遇到比自己高的人是会停止弹出操作,所以栈顶第一个人一定是比自己高的人,也就是数组中最后一个人。
res[i] = stack.length ? stack[stack.length - 1] : -1;
// 记录nums[i],因为他可能是前面的人的第一个遇到比自己高的人,不高也没关系,反正会被弹出去
stack.push(nums[i]);
};
return res;
};
大家可以尝试运行下这段代码,画图理解下,不理解没关系,下面我会画图解释这个过程:
第一次我们拿到了3,用3跟栈中做比较,结果栈是空的,没有能跟自己比较身高的人,行吧,那么3对应索引的答案就是-1,同时我们得把3加入栈中,因为很可能3是前面的人中,某个人能看到的第一个比自己高的人。

第二次比较,我们取到了4,一比较结果3还没4高,由于4是站在3前面的,4更前面的人最差就是看到自己,因为3被挡住了所以不可能被其他人看到,我们将3弹出去,此时栈又是空,对应的答案我们记录为-1,同时将4加入栈中,因为4可能是前面的人能看到的第一个更高的人。

第三次比较,我们取到了2,结果一比较2没有4高,由于栈此时不为空,那么栈顶就是比2高的人,答案记录为4,同时我们还是要将2加入栈,因为2也可能是前面的人能看到的第一个比自己高的人。

第四次比较,我们取到了1,它的情况跟第三次比较相同,没有2大,所以栈不为空,栈顶第一个就是比1大的人,记录答案为2,同时把1加入栈。

第五次比较,我们取到了2,跟栈顶第一个元素1进行比较,结果发现1没有2高,因此我们将1弹出栈。此时栈不为空,还有其他人可以继续和2比较,我们继续比,此时的栈顶是2,但2不能说比2更高,我们又得把栈顶的2弹出去,此时栈仍然不为空,继续比较。此时栈顶成了4,哎,4比2要大,那么答案记录为4,同时将2加入栈.

第六次比较已经不满足循环条件,跳出循环,我们得到了对应数组中每个元素的更大元素。
OK,那么到这里,我们详细介绍了借用单调栈解决上述例子的问题,那么如果解决文中的题目呢?其实仍然是一样的思路,题目中nums1是nums2的子集,只要我们能得出nums2中每个比自己大的元素并记录起来,再遍历nums1不就能直接得出答案了吗?
直接上代码:
var nextGreaterElement = function (nums1, nums2) {
let res = [];
let stack = [];
// 用于记录nums2中每个比自己大的值
let map = new Map();
for (let i = nums2.length - 1; i >= 0; i--) {
while (stack.length && stack[stack.length - 1] <= nums2[i]) {
stack.pop();
};
// 记录i对应的值,便于后续nums1查找
map.set(nums2[i], stack.length ? stack[stack.length - 1] : -1);
stack.push(nums2[i]);
};
for (let i = 0; i < nums1.length; i++) {
// 直接根据key取结果就好了
res.push(map.get(nums1[i]));
};
return res;
};
那么到这里本文结束。
JS Leetcode 496. 下一个更大元素 I 更清晰的图解单调栈做法的更多相关文章
- LeetCode 496. 下一个更大元素 I(Next Greater Element I) 35
496. 下一个更大元素 I 496. Next Greater Element I 题目描述 给定两个没有重复元素的数组 nums1 和 nums2,其中 nums1 是 nums2 的子集.找到 ...
- Java实现 LeetCode 496 下一个更大元素 I
496. 下一个更大元素 I 给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的下一个比其大的值. nu ...
- Leetcode 496. 下一个更大元素 I
1.题目描述 给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的下一个比其大的值. nums1 中数字 ...
- 【LeetCode】496.下一个更大元素I
496.下一个更大元素I 知识点:栈:HashMap: 题目描述 给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集. 请你找出 nums1 中每个元 ...
- LeetCode 556. 下一个更大元素 III(Next Greater Element III)
556. 下一个更大元素 III 556. Next Greater Element III 题目描述 给定一个 32 位正整数 n,你需要找到最小的 32 位整数,其与 n 中存在的位数完全相同,并 ...
- LeetCode 503. 下一个更大元素 II(Next Greater Element II)
503. 下一个更大元素 II 503. Next Greater Element II 题目描述 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素.数字 ...
- LeetCode:下一个更大元素I【31】
LeetCode:下一个更大元素I[31] 题目描述 给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的 ...
- 496. 下一个更大元素 I
496. 下一个更大元素 I 给定两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的下一个比其大的值. ...
- Leetcode 503. 下一个更大元素 II
1.题目描述 给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素.数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应 ...
- Leetcode---栈系列刷题(python3实现)----#496 下一个更大元素I
给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集.找到 nums1 中每个元素在 nums2 中的下一个比其大的值. nums1 中数字 x 的下一个更 ...
随机推荐
- mysql之力扣数据库题目620有趣的电影优化记录
闲着没事儿刷刷力扣的数据库题目,题目编号620:有趣的电影,下面是题目描述: 优化前的sql及执行时间: 优化后的sql及执行时间: 这里对筛选条件进行了优化: 1.select * 的查找效率要比逐 ...
- Asp.Net Core造轮之旅:逐步构建自己的开发框架-目录
本系列适用于已有一定.NET开发基础,学习asp.net core人士. 基础篇 asp.net core之Startup asp.net core之依赖注入 asp.net core之中间件 asp ...
- 通过 DBCA 创建 Oracle Database 21c 的进度停滞在 36%
1.问题 安装过程中一直卡在36% 检查 dbca 日志文件 位于 H:\app\trmbh\cfgtoollogs\dbca\ORCL\trace.log_2023-09-12_12-04-20PM ...
- SpringMVC06——数据绑定——2021-05-09
数据绑定介绍 在执行程序时,SpringMVC会根据客户端请求参数的不同, 将请求信息中的信息以一定的方式转换并绑定到控制器类的方法参数中. 在数据绑定过程中,SpringMVC框架会通过数据绑定组件 ...
- [转帖]修改Linux内核参数,减少TCP连接中的TIME-WAIT
https://www.cnblogs.com/xiaoleiel/p/8340346.html 一台服务器CPU和内存资源额定有限的情况下,如何提高服务器的性能是作为系统运维的重要工作.要提高Lin ...
- [转帖]46岁加入谷歌,51岁发明Go,他的编程原则影响了一大批程序员!
https://www.zhihu.com/tardis/zm/art/551945410?source_id=1005 今年3月,万众瞩目的Go 1.18版本发布,Go终于开始支持泛型了!该版本不仅 ...
- TiDB恢复部分表的方式方法
TiDB恢复部分表的方式方法 背景 今天同事告知误删了部分表. 因为是UAT准生产的环境, 所以仅有每天晚上11点的备份处理. 同时告知 昨天的数据也可以. 得到认可后进行了 TiDB的单表备份恢复. ...
- Tidb 使用minio 进行br备份数据库的过程
Tidb 使用minio 进行br备份数据库的过程 背景 br 备份恢复时一般需要共享存储. 前段时间一直使用的是nfs 进行共享文件备份. 这样需要所有的机器在 相同的目录下面挂载相同的nfs. 并 ...
- [转帖]国产数据库到底行不行?人大金仓KINGBASE数据库与主流开源数据库性能实测
近年来,人大金仓的数据库产品受到了外界诸多的关注.做产品,免不了要接受用户的对比和选择,数据库因其行业的自身特点,还有很多开源的技术产品同台比拼,用户因此也会产生诸多疑问,国产数据库相比开源数据库到底 ...
- 【转帖】通过pip命令安装好包之后,在pycharm中不显示此库,也不能调用
目录 1. 问题描述 2. 解决方法1 3. 解决方法2 1. 问题描述 在cmd输入pip list 命令可以看到我的库都已经安装好了,但是pycharm中却没有显示. 在PyCharm查找,并没有 ...