【leetcode】503. 下一个更大元素 II|刷题打卡

161 阅读2分钟

一、题目描述:

原题地址

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1:

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

提示:

注意: 输入数组的长度不会超过 10000。  

二、思路分析:

首先从条件里得知nums数组是个循环数组,也就是说遍历完一遍nums数组,还能继续从头遍历。那么这个下一个更大元素2.0版本和之前1.0版本最大的不同就是目标元素的遍历范围。

1.0版本请参照另一篇文章

  1. 确认遍历范围和顺序nums.slice(targetIndex + 1, nums.length - 1)nums.slice(0, targetIndex), 所以可以把数组重复遍历两边,来满足所有元素的遍历范围。

  2. 通过辅助栈,记录遍历过程中还未匹配到下一个更大元素的元素的索引。(此处记录索引而不是元素,因为元素内容不唯一。)

  3. 注意栈中记录的元素下标。因为上述遍历范围是nums.length * 2,所以同一个元素的会对应两个下标,此处可以通过 index%nums.length获取正确的索引。

示例:

nums = [3,2,1,4] 当前元素: target, 辅助栈 stack:

step1:确认遍历范围[5,3,2,1,4,5,3,2,1,4]
step2: target = 5, 入栈。 stack: [5]
step3: target = 3,3 < 5(stack.top), 入栈。stack: [5, 3]
step4:target = 2,2 < 3(stack.top),入栈。 stack: [5, 3, 2]
step5:target = 1,1 < 2(stack.top),入栈。 stack: [5, 3, 2, 1]
step6:target = 4, 4 > stack.top即4 > 1, 1出栈,记录元素1对应的下一个更大值为4。stack: [5, 3, 2]
step7:继续比较target和新的stack.top, 直到栈为空或者target < stack.top。此处直到3和2出栈,stack=[5], 4 < 5, 循环结束。此时,target = 4,入栈。stack:[5, 4]
step8:target = 5, 5 > 4即target > stack.top,出栈。 所以4的下一个更大元素是5,但是元素5的真正idx是0, 所以索引记录为0。5入栈。stack:[5, 5]
step9:target = 3
step10:target = 2
step11:target = 1
step12:target = 4
循环结束

三、AC 代码:

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var nextGreaterElements = function(nums) {
    let s = [];
    const len = nums.length;
    let t = Array.from({length: len}, i => -1);
    let i = 0;
    while(i < len * 2) {
        while (s.length && nums[i % len] > nums[s.slice(-1)]) {
            t[s.pop()] = nums[i % len];
        }
        s.push(i % len);
        i++;
    }
    return t;
};

四、总结:

明白条件的意义,比如循环数组的本质就是一个类似环的数据结构。最后我们只需将数组复制一份就能满足每个元素需要的便利范围。

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情