LeetCode - 496 下一个更大元素 I

题目来源

496. 下一个更大元素 I - 力扣(LeetCode)

题目描述

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

题目解析

本题可以使用 "单调栈" 解题。

单调栈,即栈内(从栈底到栈顶)元素呈现单调递减或单调递增性质。

本题要求每个元素的下一个更大元素,则可以使用单调递减栈

具体应用逻辑如下:

  • 遍历 nums 数组的每个元素 num,尝试压入 stack,但是压栈前,需要和 stack.top 栈顶元素比较大小:
  1. 若 stack 为空 或者 num ≤ stack.top,则 num 压栈后,不会破坏 stack 的(非严格)单调递减性质,此时 num 可以直接压栈。

  2. 若 num > stack.top,则 num 压栈后,会破坏 stack 的单调递减性质,此时我们应该将 stack.top 弹出。

    stack.top 弹栈的同时,意味着 stack.top 元素找到了它的下一个更大元素(即:num)。

    stack.top 弹栈完成后,此时 num 还需要继续和新的栈顶元素进行比较大小,循环上面逻辑,直到 stack 为空或者 num ≤ stack.top,才能将 num 压入 stack。

C算法源码

cpp 复制代码
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* nextGreaterElement(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize) {
    int nextBigger[10001];
    for (int i = 0; i <= 10000; i++) {
        nextBigger[i] = -1;
    }

    // (非严格)单调递减栈, 即栈底(索引0位置) 到栈顶(索引stack_size-1位置)的元素是(非严格)单调递减的
    int stack[1000];
    int stack_size = 0;

    // 遍历 nums2 的元素 nums2[i]
    for (int i = 0; i < nums2Size; i++) {
        // 若 stack 非空 且 nums2[i] > stack.top, 则此时 nums2[i] 压栈会破坏 stack 的(非严格)单调递减性质
        while (stack_size > 0 && nums2[i] > stack[stack_size - 1]) {
            // 因此我们需要将 stack.top 弹栈, 弹栈的同时,我们也找到了 stack.top 的下一个更大元素(即为:nums2[i])
            nextBigger[stack[--stack_size]] = nums2[i];
        }

        // 当 stack 为空 或 nums2[i] ≤ stack.top,则此时 nums2[i] 压栈不会破坏 stack 的(非严格)单调递减性质
        stack[stack_size++] = nums2[i];
    }

    int* ans = (int*) malloc(sizeof(int) * nums1Size);
    for (int i = 0; i < nums1Size; i++) {
        ans[i] = nextBigger[nums1[i]];
    }

    *returnSize = nums1Size;

    return ans;
}

C++算法源码

cpp 复制代码
class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        map<int, int> nextBigger;

        // (非严格)单调递减栈, 即栈底到栈顶的元素是(非严格)单调递减的
        deque<int> stack;

        // 遍历 nums2 的元素 num
        for (int num : nums2) {
            // 若 stack 非空 且 num > stack.top, 则此时 num 压栈会破坏 stack 的(非严格)单调递减性质
            while (!stack.empty() && num > stack.back()) {
                // 因此我们需要将 stack.top 弹栈, 弹栈的同时,我们也找到了 stack.top 的下一个更大元素(即为:num)
                nextBigger[stack.back()] = num;
                stack.pop_back();
            }

            // 当 stack 为空 或 num ≤ stack.top,则此时 num 压栈不会破坏 stack 的(非严格)单调递减性质
            stack.push_back(num);
        }

        vector<int> ans(nums1.size());
        for (int i = 0; i < nums1.size(); i++) {
            if (nextBigger.find(nums1[i]) != nextBigger.end()) {
                ans[i] = nextBigger[nums1[i]];
            } else {
                ans[i] = -1;
            }
        }

        return ans;
    }
};

JS算法源码

javascript 复制代码
/**
 * @param {number[]} nums1
 * @param {number[]} nums2
 * @return {number[]}
 */
var nextGreaterElement = function (nums1, nums2) {
    const nextBigger = {};

    // (非严格)单调递减栈, 即栈底到栈顶的元素是(非严格)单调递减的
    const stack = [];
    
    // 遍历 nums2 的元素 num
    for (let num of nums2) {
        // 若 stack 非空 且 num > stack.top, 则此时 num 压栈会破坏 stack 的(非严格)单调递减性质
        while (stack.length > 0 && num > stack.at(-1)) {
            // 因此我们需要将 stack.top 弹栈, 弹栈的同时,我们也找到了 stack.top 的下一个更大元素(即为:num)
            nextBigger[stack.pop()] = num;
        }

        // 当 stack 为空 或 num ≤ stack.top,则此时 num 压栈不会破坏 stack 的(非严格)单调递减性质
        stack.push(num);
    }

    const ans = new Array(nums1.length);
    for (let i = 0; i < nums1.length; i++) {
        ans[i] = nextBigger[nums1[i]] ?? -1;
    }

    return ans;
};

Java算法源码

java 复制代码
class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        HashMap<Integer, Integer> nextBigger = new HashMap<>();

        // (非严格)单调递减栈, 即栈底到栈顶的元素是(非严格)单调递减的
        ArrayDeque<Integer> stack = new ArrayDeque<>();

        // 遍历 nums2 的元素 num
        for (int num : nums2) {
            // 若 stack 非空 且 num > stack.top, 则此时 num 压栈会破坏 stack 的(非严格)单调递减性质
            while (!stack.isEmpty() && num > stack.peek()) {
                // 因此我们需要将 stack.top 弹栈, 弹栈的同时,我们也找到了 stack.top 的下一个更大元素(即为:num)
                nextBigger.put(stack.pop(), num);
            }

            // 当 stack 为空 或 num ≤ stack.top,则此时 num 压栈不会破坏 stack 的(非严格)单调递减性质
            stack.push(num);
        }

        int[] ans = new int[nums1.length];
        for (int i = 0; i < nums1.length; i++) {
            ans[i] = nextBigger.getOrDefault(nums1[i], -1);
        }

        return ans;
    }
}

Python算法源码

python 复制代码
class Solution(object):
    def nextGreaterElement(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: List[int]
        """
        nextBigger = {}

        # (非严格)单调递减栈, 即栈底到栈顶的元素是(非严格)单调递减的
        stack = []

        # 遍历 nums2 的元素 num
        for num in nums2:
            # 若 stack 非空 且 num > stack.top, 则此时 num 压栈会破坏 stack 的(非严格)单调递减性质
            while stack and num > stack[-1]:
                # 因此我们需要将 stack.top 弹栈, 弹栈的同时,我们也找到了 stack.top 的下一个更大元素(即为:num)
                nextBigger[stack.pop()] = num
            
            # 当 stack 为空 或 num ≤ stack.top,则此时 num 压栈不会破坏 stack 的(非严格)单调递减性质
            stack.append(num)
        
        ans = []
        for num in nums1:
            ans.append(nextBigger.get(num, -1))
        
        return ans
相关推荐
jie*1 分钟前
小杰深度学习(sixteen)——视觉-经典神经网络——MobileNetV2
人工智能·python·深度学习·神经网络·tensorflow·numpy·matplotlib
CoderCodingNo13 分钟前
【GESP】C++五级考试大纲知识点梳理, (3-4) 链表-双向循环链表
开发语言·c++·链表
whltaoin14 分钟前
AI 超级智能体全栈项目阶段五:RAG 四大流程详解、最佳实践与调优(基于 Spring AI 实现)
java·人工智能·spring·rag·springai
junnhwan15 分钟前
【苍穹外卖笔记】Day05--Redis入门与店铺营业状态设置
java·数据库·redis·笔记·后端·苍穹外卖
一枚前端小能手16 分钟前
🚀 巨型列表渲染卡顿?这几个优化技巧让你的页面丝滑如德芙
前端·javascript
酷柚易汛智推官16 分钟前
Electron技术深度解析:跨平台桌面开发的利器与挑战
前端·javascript·electron
llz_11221 分钟前
第五周作业(JavaScript)
开发语言·前端·javascript
colus_SEU27 分钟前
【编译原理笔记】2.1 Programming Language Basics
c++·算法·编译原理
曾经的三心草28 分钟前
OpenCV4-直方图与傅里叶变换-项目实战-信用卡数字识别
python·opencv·计算机视觉
摇滚侠34 分钟前
Spring Boot 3零基础教程,Spring Boot 特性介绍,笔记02
java·spring boot·笔记