寻找数组中下一个更大的元素

本文介绍了如何寻找数组中每个元素的下一个更大元素,通过分析给出的示例数组,提出利用递减序列的思想降低时间复杂度。文章引用了三道LeetCode题目,包括链表和数组的场景,讲解了如何找到链表和数组中每个元素的下一个更大元素,当不存在时返回特定值。并提供了简洁的AC代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先定义数组中下一个更大元素:数组中某个元素下一个更大元素指的是在这个数字右边第一个大于该元素的值。例如【5,4,11,3,10】:5的下一个最大元素是11;4的下一个最大元素是11;11没有下一个最大元素;3的下一个最大元素是10;10没有下一个最大元素;

题目:给你一个整型数组,返回数组中每个元素的下一个更大元素数组,如果某个元素不存在最大数组,返回-1(假设给定的数组中不存在-1)。

输入:[3, 1, 1, 9, 9, 1, 3, 0, 5, 5]
输出:[9, 9, 9, -1, -1, 3, 5, 5, -1, -1]

题目来源:这道题是我根据下面两道LeetCode上的原题改编的,作为一个很好的引子。

分析:显然,两层循环就解决问题了,这样时间复杂度为O(n^2),显然不是我们要讨论的最优解了。我们考虑这样一个数组【6,5,4,3,2,7】,显然前面6,5,4,3,2的下一个更大元素均为7。受到这个启发,我们可以维护一个递减序列,每当出现不是递减序列时,我们依次查看该元素是否大于前面的元素,如果大于就为该元素的下一个元素。

以【7,6,5,4,3,5】为例,显然前面的7,6,5,4,3位递减序列,最后一位5违反了这个规则,我们依次向前看:5>3,所以3的下一个最大元素为5;5>4,所以4的下一个最大元素为5;5 !> (不大于)5,所以5的下一个更大元素不是5;前面的6,7就不用检查了,因为他们比5还要大,记住我们维护了一个递减序列。

下面看实现代码:

    private int[] nextGreaterElement(int[] nums) {
        if (nums == null || nums.length == 0) return new int[0];
        Stack<Integer> st = new Stack<>();
        int[] res = new int[nums.length];
        Arrays.fill(res, -1);
        for (int i = 0; i < nums.length; i++) {
            while (!st.isEmpty() && nums[i] > nums[st.peek()]) {
                res[st.pop()] = nums[i];
            }
            st.push(i);
        }
        return res;
    }

有了上面的基础,我们来看两道LeetCode上的原题:

LeetCode--1019. Next Greater Node In Linked List

原题目:

We are given a linked list with head as the first node.  Let's number the nodes in the list: node_1, node_2, node_3, ... etc.

Each node may have a next larger value: for node_inext_larger(node_i) is the node_j.val such that j > inode_j.val > node_i.val, and j is the smallest possible choice.  If such a j does not exist, the next larger value is 0.

Return an array of integers answer, where answer[i] = next_larger(node_{i+1}).

Note that in the example inputs (not outputs) below, arrays such as [2,1,5] represent the serialization of a linked list with a head node value of 2, second node value of 1, and third node value of 5.

Example 1:

Input: [2,1,5]
Output: [5,5,0]

Example 2:

Input: [2,7,4,3,5]
Output: [7,0,5,5,0]

Example 3:

Input: [1,7,5,1,9,2,5,1]
Output: [7,9,9,9,0,5,0,0]

Note:

  1. 1 <= node.val <= 10^9 for each node in the linked list.
  2. The given list has length in the range [0, 10000].

意思就是说给我们的是一个链表,返回最大元素,不存在是返回0。这里我们先将链表转化为数组,然后进行求解:

AC代码:

    public int[] nextLargerNodes(ListNode head) {
        if (head == null) {
            return new int[0];
        }
        List<Integer> list = new ArrayList<>();
        while (head != null) {
            list.add(head.val);
            head = head.next;
        }
        Stack<Integer> stack = new Stack<>();
        int[] res = new int[list.size()];
        for (int i = 0; i < res.length; i++) {
            while (!stack.isEmpty() && list.get(i) > list.get(stack.peek())) {
                res[stack.pop()] = list.get(i);
            }
            stack.push(i);
        }
        return res;
    }

LeetCode--496. Next Greater Element I

原题目:

You are given two arrays (without duplicates) nums1 and nums2 where nums1’s elements are subset of nums2. Find all the next greater numbers for nums1's elements in the corresponding places of nums2.

The Next Greater Number of a number x in nums1 is the first greater number to its right in nums2. If it does not exist, output -1 for this number.

Example 1:

Input: nums1 = [4,1,2], nums2 = [1,3,4,2].
Output: [-1,3,-1]
Explanation:
    For number 4 in the first array, you cannot find the next greater number for it in the second array, so output -1.
    For number 1 in the first array, the next greater number for it in the second array is 3.
    For number 2 in the first array, there is no next greater number for it in the second array, so output -1.

Example 2:

Input: nums1 = [2,4], nums2 = [1,2,3,4].
Output: [3,-1]
Explanation:
    For number 2 in the first array, the next greater number for it in the second array is 3.
    For number 4 in the first array, there is no next greater number for it in the second array, so output -1.

Note:

  1. All elements in nums1 and nums2 are unique.
  2. The length of both nums1 and nums2 would not exceed 1000.

给了两个数组,其中一个是另外一个的子数组,找出子数组中每个元素在原数组中的下一个元素。这里我们先对原数组进行预处理,得到原数组的所有元素的下一个更大元素。保持在hashmap里面,然后在遍历子数组,下面看AC代码:

    public int[] nextGreaterElement(int[] findNum, int[] nums) {
        if (findNum == null || findNum.length == 0 || nums == null || nums.length == 0) return new int[0];
        int[] res = new int[findNum.length];
        Map<Integer, Integer> map = new HashMap<>();
        Deque<Integer> stack = new ArrayDeque<>();
        for (int i = 0; i < nums.length; i++) {
            while (!stack.isEmpty() && nums[i] > stack.peek()) {
                map.put(stack.pop(), nums[i]);
            }
            stack.push(nums[i]);
        }
        for (int i = 0; i < findNum.length; i++) {
            res[i] = map.getOrDefault(findNum[i], -1);
        }
        return res;
    }

LeetCode--503. Next Greater Element II

原题目:

   Given a circular array (the next element of the last element is the first element of the array), print the Next Greater Number for every element. The Next Greater Number of a number x is the first greater number to its traversing-order next in the array, which means you could search circularly to find its next greater number. If it doesn't exist, output -1 for this number.

Example 1:

Input: [1,2,1]
Output: [2,-1,2]
Explanation: The first 1's next greater number is 2; 
The number 2 can't find next greater number; 
The second 1's next greater number needs to search circularly, which is also 2.

Note: The length of given array won't exceed 10000.

这题与我们最开始的引题唯一的区别就是,引题找下一个最大元素找到数组的末尾,本题是找到末尾了接着从头开始找,相当于一个循环数组。其实遍历两遍就可以了,下面看AC代码:

    public int[] nextGreaterElements(int[] nums) {
        if (nums == null || nums.length == 0) return new int[0];
        Stack<Integer> st = new Stack<>();
        int[] res = new int[nums.length];
        Arrays.fill(res, -1);
        for (int i = 0; i < nums.length; i++) {
            while (!st.isEmpty() && nums[i] > nums[st.peek()]) {
                res[st.pop()] = nums[i];
            }
            st.push(i);
        }
        for (int i = 0; i < nums.length; ++i) {
            while (!st.isEmpty() && nums[i] > nums[st.peek()]) {
                res[st.pop()] = nums[i];
            }
        }
        return res;
    }

如果你觉得上面的代码有冗余,也可以写成这样:

    public static int[] nextGreaterElements(int[] nums) {
        if (nums == null || nums.length == 0) return new int[0];
        int n = nums.length;
        Stack<Integer> st = new Stack<>();
        int[] res = new int[n];
        Arrays.fill(res, -1);
        for (int i = 0; i < 2 * n; i++) {
            int num = nums[i%n];
            while (!st.isEmpty() && num> nums[st.peek()]) {
                res[st.pop()] = num;
            }
            if (i < n) st.push(i);
        }
        return res;
    }

其实是一样的!

 

好了,我们下期见!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值