leetcode - Next Greater Element I-III - Java

博客内容讲述了如何使用栈高效地解决数组中查找下一个更大元素的问题,包括两种情况:一是数组元素无重复,二是数组元素可重复。博主首先介绍了暴力破解的方法,然后展示了更优的解决方案,即通过一次遍历和栈操作实现。在第二种情况下,通过存储数组下标而不是元素本身来处理重复元素。此外,还讨论了一个寻找具有相同数字但值更大的最小整数的问题,同样使用了转换数组和寻找交换位置的策略。

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

遇到了一道Easy题,这个Easy在于解起来很好解,但最优解实在不好想(现在的我是真想不太出来,看题看少了,读书读少了):
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.

大致就是给定两个数组,其中A数组中的元素都来自B数组,且里边的元素都是独一无二的,没有重复的。返回A数组中每一个当前元素在B数组中的下一个比当前元素大的元素,如果没有则为-1。
先来个自己写的lj解法,暴力到不能再暴力:

    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int[] ans = new int[nums1.length];
        Stack<Integer> s;
        int n = nums2.length;
        Arrays.fill(ans,-1);
        
        for (int i = 0; i < nums1.length; i++) {
            s = new Stack<>();
            for (int j = n - 1; j >= 0; j--) {
                s.push(nums2[j]);
            }
            int peek = s.peek();
            while (peek != nums1[i]) {
                s.pop();
                peek = s.peek();
            }
            while (!s.empty()){
                if((peek = s.peek()) > nums1[i]){
                    ans[i] = peek;
                    break;
                }
                s.pop();
            }
        }
        return ans;
    }

不想写注释了,自己的代码都看不下去了,我已经不想知道我把每个元素入栈出栈多少次了。

看一下大佬的解法:先说一下思路,大佬的解法只把nums2中的每个元素入栈/出栈了一次

  • 对于每一个数,都与栈中的上一个元素比较
    • 如果大于栈中的上一个元素,那么这个元素就是上一个元素应该查到的结果,并且将其pop掉,存入map进行记录;循环直到stack为空或者查到元素大于当前元素(这一步保证了栈中的元素是数值递减的)
    • 如果栈中没有值,或者小于栈中Top元素则压入栈
  • 最后用nums1中的元素在map中进行查询,替换结果
/**
 * 这个解法巧妙之处在于,利用了findNums中的所有元素都是nums的子元素,
 * 利用nums将所有的
 */
public class NextGreaterElementIDiss {

    public int[] nextGreaterElement(int[] findNums, int[] nums) {
        HashMap<Integer, Integer> map = new HashMap<>();
        Stack<Integer> stack = new Stack<>();
        for (int num : nums) {
            while (!stack.isEmpty() && stack.peek() < num){
                map.put(stack.pop(),num);
            }
            stack.push(num);
        }
        for (int i = 0; i < findNums.length; i++) {
            findNums[i] = map.getOrDefault(findNums[i],-1);
        }
        return findNums;
    }
}

What can I say?下边又做了这个系列的II,当然也是用栈,并且栈中元素也绝对是递减的,题目藐视在上一道题的基础上做了修改:1.数组中的元素可重复 2.在查询时可循环查询,比如[1,2,1] 返回[2,-1,2]。
思想:
1.这个循环查询,最多循环一次,我们可以写为把数组复制一份放在后边(抽象)
2.我们可以在stack中存放数组下标,而非数组中的元素,因为元素是有重复的

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

III:Given a positive integer n, find the smallest integer which has exactly the same digits existing in the integer n and is greater in value than n. If no such positive integer exists, return -1.

Note that the returned integer should fit in 32-bit integer, if there is a valid answer but it does not fit in 32-bit integer, return -1.

Example 1:

Input: n = 12
Output: 21

Example 2:

Input: n = 21
Output: -1

第三题就有点大不一样了,给一个数字,在数字组成相同的情况下寻找比当前数大的最小的数。
思路:

  • 第一步还是将数字转成数组的形式
  • 如果一个数所有数字都是按从大到小排列,那么同样的数字再也找不出比该数字更大的数了
  • 想要找到比当前数大的最小数,就需要从低位开始找,直到找到一位小于后一位,这样说明有比当前数更大的数,起码两者做交换就产生了一个更大的数
  • 但这可能并不是比当前数大的最小数,我们需要向低位找比当前位数大的最小数,做交换
    代码:
    public int nextGreaterElement(int n) {
        char[] number = (n + " ").toCharArray();
        int len = number.length,i,j;
        //找增序的数组位置
        for (i = len - 1;i > 0;i--){
            if(number[i-1] < number[i]){
                break;
            }
        }
        //如果i=0则说明没有比当前数更大的数
        if (i==0){
            return -1;
        }
        int x = number[i-1],smallest = i;
        for(j = i+1; j < len;j++){
            //去后面找最小的元素
            if(number[j] > x && number[j] < number[smallest]){
                smallest = j;
            }
        }
        char tmp = number[smallest];
        number[smallest] = number[i-1];
        number[i-1] = tmp;

        Arrays.sort(number,i,len);
        long val = Long.parseLong(new String(number));
        return val > Integer.MAX_VALUE ? -1 : (int)val;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值