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
相关推荐
Манго нектар1 分钟前
JavaScript的条件语句
前端·javascript
予早6 分钟前
LeetCode 149. 直线上最多的点数
算法·leetcode
诚丞成8 分钟前
算法的时间复杂度和空间复杂度
开发语言·数据结构·算法
君子剑mango9 分钟前
Spring @Import
java·spring
Jason-河山10 分钟前
Java爬虫抓取数据的艺术
java·爬虫·python
全貌13 分钟前
C++笔记 --基本语法(命名空间/函数重载/缺省参数/引用/inline/nulltpr)
开发语言·c++·笔记
深度学习的奋斗者14 分钟前
YOLOv8+注意力机制+PyQt5玉米病害检测系统完整资源集合
python·深度学习·yolo
百成Java15 分钟前
基于springboot的旅游网站
java·spring boot·后端·mysql·spring·智能家居·旅游
—你的鼬先生16 分钟前
从零开始使用树莓派debian系统使用opencv4.10.0进行人脸识别(保姆级教程)
python·opencv·debian·人脸识别·二维码识别·opencv安装
斯派的曼17 分钟前
学习C++的第七天!
开发语言·c++·学习