代码随想录算法训练营day61 || 739. 每日温度,496.下一个更大元素 I

本文介绍了如何使用单调栈解决LeetCode中的两个问题:739.每日温度和496.下一个更大元素,分别阐述了两种解题思路,分析了时间复杂度和空间复杂度,并强调了单调栈在寻找右侧更大元素中的关键作用。
摘要由CSDN通过智能技术生成

单调栈,你该了解的,这里都讲了!LeetCode:739.每日温度_哔哩哔哩_bilibili

单调栈,套上一个壳子就有点绕了| LeetCode:496.下一个更大元素_哔哩哔哩_bilibili

 739. 每日温度

思路:单调栈

// 时间复杂度O(n)~O(n^2)
// 空间复杂度O(n)

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        if(temperatures.length == 1)
            return new int[]{0};

        int n = temperatures.length;
        
        int[] answer = new int[n];
        List<Integer> list = new ArrayList<>();
        
        for(int i=n-1; i>=0; i--){
            // 注意temperatures 数组中可能会存在重复元素,因此比较大小是大于等于,从而找到右侧大于自己的元素,而不能把等于自己的元素也算进去
            while(list.size()>0 && temperatures[i] >= temperatures[list.get(list.size()-1)]){
                list.remove(list.size()-1);
            }
            if(list.size() == 0)
                answer[i] = 0;
            else{
                // 取得当前大于nums[i]的首个右侧元素,即栈首,但存储的是那个元素的下标
                int idx = list.get(list.size()-1);
                answer[i] = idx-i;
            }
            list.add(i);
        }
        return answer;
   }

}

496.下一个更大元素 I

思路:单调栈

// 时间复杂度O(n)~O(n^2)
// 空间复杂度O(n)

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        // // 能想到的首要的解题策略是暴力法,时间复杂度是O(n^2)

        // // 采用单调栈的方法进行求解
        // // 针对找右侧出现第一个大于目标数字的数,我们遍历的顺序是对目标数组从前往后遍历,且单调栈构建之后是从栈首到栈底是递增的
        Map<Integer, Integer> map = new HashMap<>();
        Stack<Integer> stack = new Stack<>();
        int[] ans = new int[nums1.length];

        // // 这一步操作非常的关键,如果没有这步操作的话,那些被压入栈但是不出栈的元素将始终得不到其在nums1是否存在的判断,那么ans中相应的位置也不会得到赋值
        // Arrays.fill(ans, -1);
        // // 一定是数作为键,下标作为value,因为nums1和nums2在数值上是存在交集,而不是在下标上
        for(int i=0; i<nums1.length; i++)
            map.put(nums1[i], i);
        
        // for(int i=0; i<nums2.length; i++){
        //     // 出现更大的元素,则需要对栈开始出栈元素
        //     while(!stack.isEmpty() && nums2[i] > nums2[stack.peek()]){
        //         // 获取被出栈的元素,并且对于ans的赋值就是在此操作
        //         int idx = stack.pop();  
        //         if(map.containsKey(nums2[idx])){
        //             int j = map.get(nums2[idx]);
        //             ans[j] = nums2[i];
        //         }
        //     }
        //     stack.push(i);
        // }
        // return ans;

        // 使用与739题保持一致的方式进行求解
        for(int i=nums2.length-1; i>=0; i--){
            while(!stack.isEmpty() && nums2[i] > nums2[stack.peek()])
                stack.pop();

            // 栈本身就为空,或者是把所有元素都弹出了,那么自然当前的这个数字在nums2的当前位置的右侧没有更大的元素了   
            if(stack.isEmpty()){
                if(map.containsKey(nums2[i]))
                    ans[map.get(nums2[i])] = -1;
            }  
            else{
                // 可以在栈内找到一个更大的元素,由于数组是从右侧开始遍历的,所以一定是位于右侧的,并且栈内是递增的,所以一定保存的最近大于当前nums2[i]的,因为如果是nums2[i] = 1, 4,2应该选4,  2,4应该选2
                int idx = stack.peek();
                if(map.containsKey(nums2[i]))
                    ans[map.get(nums2[i])] = nums2[idx];
            }
            stack.push(i);
        }


        return ans;
    }
}

心得:

  • 单调栈,找右侧第一个大的元素。从左向右遍历,出栈小于当前位置元素的栈内元素,且在出栈时进行结果的更新。如果不出栈的元素,则得不到更新,因此依赖初始化动作去赋值;
  • 从右向左遍历,每一个元素仍然进行批量出栈,在批量出栈动作结束后,再进行对当前元素位置结果操作的一次更新。此方式可以根据批量出栈操作后,栈内是否还存在元素来判断当前位置元素是否有可行的目标,是填入-1还是其他下标值。
  • 总体而言第一种思路更直观。第二种方法更为的全面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值