代码随想录day57 单调栈

代码随想录day57 单调栈

题739 每日温度

1,暴力解法两层循环搜索,超时了。

2,如何想到单调栈:
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。

3, 使用单调栈时需要明确几点:

  • 单调栈里存放的元素是什么: 本题存放的是下标。
  • 单调栈里元素是递增还是递减: 本题中从栈头到栈底一次性递增,也就是栈底存放的是大数。
  • 有3种条件需要判断:
    • 当前遍历元素T[i] < 栈顶元素
    • 当前遍历元素T[i] = 栈顶元素
    • 当前遍历元素T[i] > 栈顶元素
  1. 对于本题,栈里存放的是下标,以temperature = [73,74,75,71,69,72,76,73]为例,
    先将73的下标0放入单调栈,再将74(1 代表下标)放入的时候74 > 73,因为栈从栈头到栈底是单调递增,则此时需要将73弹出再将74放入,相当于找到了原数组右边比73大的元素,但是第几个元素呢,就是74的下标1减去73的下标0 ,result[0] = 1 - 0。
    之后再放入75(2),弹出74(1),result[1] = 2 - 1=1.
    再放入71(3),此时71 < 75,相当于还没有找到比75大的元素,直接将71的下标放入栈中,继续遍历。
    69(4)< 71(3),下标放入栈中。
    72(5)> 69(4),找到了比69大的元素,因此result[4] = 5 - 4 = 1,弹出69(4),此时栈顶元素变为71(3),72(5)> 71(3),找到了比71(3)大的元素72(5),因此result[3] = 5 - 3 = 2, 继续弹出71(3),此时72(5)< 75(2),将72(5)放入栈中,以此类推。
    5,从上面的过程中不难看出,当 temperature[i] > temperature[stack.peek()] 时,result[stack.peek()] = i - stack.peek()。
class Solution {
    //暴力解法,时间复杂度超了
    // public int[] dailyTemperatures(int[] temperatures) {
    //     int[] result = new int[temperatures.length];
    //     for(int i = 0; i < temperatures.length; i++){
    //         for(int j = i + 1 ; j < temperatures.length; j++){
    //             if(temperatures[j] > temperatures[i]){
    //                 result[i] = j - i;
    //                 break;
    //             }
    //             result[i] = 0;
    //         }
    //     }
    //     return result;
    // }

    /**
     --采用单调栈,栈中存放的是元素的下标,从栈顶开始元素按照依次递增的顺序。
     --当需要在数组中寻找任意一个元素的右边或者左边第一个比自己大或者小的元素的位置时
     想到用单调栈。
     */
    public int[] dailyTemperatures(int[] temperatures){
        Deque<Integer> stack = new LinkedList<>();
        int len = temperatures.length;
        int[] result = new int[len];
        for(int i = 0; i < len; i++){
            while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
                int top = stack.pop();
                result[top] = i - top;
            } 
            stack.push(i);
        }
        return result;
    }

}

题496 下一个更大元素1

1,本题暴力解法可以通过。
2,单调栈的做法比上题多拐了个弯,先用上题中的方法遍历nums2,找到其中各个元素的下一个更大元素,同时对于nums2[i], 判断是否存在于nums1中,如果存在就找到该元素在nums1的下标。
3,要快速找到数组中元素的下标,可以用map,由于本题中元素各不相同,因此可以将值作为key,下标作为value。

class Solution {
    //暴力解法:先找到相同元素的位置,再在nums2中寻找第一个更大的元素。
    // public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    //     int[] result = new int[nums1.length];
    //     Arrays.fill(result, -1);
    //     for(int i = 0; i < nums1.length; i++) {
    //         int a = -1;
    //         for(int j = 0; j < nums2.length; j++) {
    //             if(nums1[i] == nums2[j]) {
    //                 a = j;
    //                 break;
    //             }
    //         }
    //         if(a != -1) {
    //             for(int k = a + 1; k < nums2.length; k++) {
    //                 if(nums2[k] > nums1[i]) {
    //                     result[i] = nums2[k];
    //                     break;
    //                 }
    //             } 
    //         }
    //     }
    //     return result;
    // }

    /**
    单调栈解法:对nums2求其中每个元素右边比其大的第一个元素,再判断该元素在nums1中是否存在及索引位置。
    想要快速找到一个元素在某个数组中的索引,可以将数组用一个map表示,本题中数组元素不重复,可以将元素值作为key,下标作为value
     */
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        Map<Integer,Integer> map = new HashMap<>();
        for(int i = 0; i < nums1.length; i++) {
            map.put(nums1[i], i);
        }
        Deque<Integer> stack = new LinkedList<>();
        int[] result = new int[nums1.length];
        Arrays.fill(result, -1);
        for(int i = 0; i < nums2.length; i++) {
            while(!stack.isEmpty() && stack.peek() < nums2[i]) {
                int top = stack.pop();
                if(map.containsKey(top)) {
                    result[map.get(top)] = nums2[i];
                }
            }
            stack.push(nums2[i]);
        }
        return result;
    }

}

你可能感兴趣的:(leetcode,算法,数据结构,java)