代码随想录动态规划 || 739 496 503 42 84 || 代码随想录一刷总结!

Day50

739. 每日温度

力扣题目链接

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

思路

  • 使用一个单调栈处理

  • 第一个元素下标入栈,然后每次比较一下peek位置的元素和第i个元素,如果大就弹出,弹到小入栈,并记录res数组值

代码

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        LinkedList stack = new LinkedList<>();
        int[] res = new int[temperatures.length];
        stack.push(0);
        for (int i = 1; i < temperatures.length; i++){
            while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){
                int temp = stack.pop();
                res[temp] = i - temp;
            }
            stack.push(i);
        }
        return res;
    }
}

496.下一个更大元素 I

力扣题目链接

给你两个 没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。

请你找出 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出 -1 。

思路

  • 理清楚逻辑,nums1记录一个哈希表,遍历nums2,使用单调栈,如果要加入的比栈顶大,就弹出,弹出之后其实就找到了栈顶这个元素在nums2中比他大的下一个元素,因为nums1是nums2的子集,所以这个元素在nums1中不一定有,要判断一下,确实有了再记录到res数组中

代码

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        Map map = new HashMap<>();
        for (int i = 0; i < nums1.length; i++){
            map.put(nums1[i],i);//建立哈希表
        }
        LinkedList stack = new LinkedList<>();
        int[] res = new int[nums1.length];
        Arrays.fill(res,-1);//初始化为-1,最后单调栈中会剩余元素,默认res中对应位置为-1
        stack.push(nums2[0]);
        for (int i = 1; i < nums2.length; i++){
            while (!stack.isEmpty() && nums2[i] > stack.peek()){
                int temp = stack.pop();
                if (map.containsKey(temp)){//要判断一下哈希表中是否有这个key
                    res[map.get(temp)] = nums2[i];//有的话才更新res数组
                }
            }
            stack.push(nums2[i]);//别忘了循环结束要把元素加进来
        }
        return res;
    }
}

503.下一个更大元素II

力扣题目链接

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

思路

  • 和上一道题整体思路差不多,不需要建立哈希表,因为是同一个数组

  • 主要是循环数组的处理,可以遍历两遍数组,注意使用取余运算

代码

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

42.接雨水

力扣题目链接

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

思路

  • 方法一:暴力遍历

  • 首先注意,第一个位置和最后一个位置不能装雨水

  • 每个位置能装的雨水的量取决于,它左侧和右侧最大元素中更小的那个(木桶壁)

  • 因此可以使用双层循环遍历,遍历数组,每一个位置都去找左侧和右侧最大的元素,求出这个位置能装雨水的量,然后相加

  • 方法二:双指针优化

  • 使用两个数组记录每个元素它左侧元素最大值和右侧元素最大值

  • 这样可以把时间复杂度降到O(n)

  • 方法三:单调栈

  • 使用单调栈处理,一旦发现后一个元素比前一个大,说明出现了凹槽,则可能要装雨水

  • 栈中pop的元素是要装雨水的位置

  • 栈中再peek的元素是左侧的最大值(因为是单调栈)

  • 这时遍历到的元素是右侧的墙壁,这时就考虑装雨水,面积是长×宽

代码

class Solution {
    public int trap(int[] height) {
        int sum = 0;
        for (int i = 0; i < height.length; i++){
            if (i == 0 || i == height.length - 1) continue;//剪枝操作
            int heightL = height[i];
            int heightR = height[i];
            for (int j = i; j >= 0; j--){
                heightL = Math.max(heightL,height[j]);//左侧最大元素
            }
            for (int j = i; j < height.length; j++){
                heightR = Math.max(heightR,height[j]);//右侧最大元素
            }
            int temp = Math.min(heightL,heightR) - height[i];//这个位置装雨水量
            if (temp > 0) sum += temp;//加和,注意判断是否大于0
        }
        return sum;
    }
}

class Solution1 {
    public int trap(int[] height) {
        int sum = 0;
        int[] heightL = new int[height.length];
        int[] heightR = new int[height.length];
        heightL[0] = height[0];
        for (int i = 1; i < height.length; i++){
            heightL[i] = Math.max(heightL[i - 1], height[i]);
        }
        heightR[height.length - 1] = height[height.length - 1];
        for (int i = height.length - 2; i >= 0; i--){
            heightR[i] = Math.max(heightR[i + 1], height[i]);
        }
        for (int i = 0; i < height.length; i++){
            int temp = Math.min(heightL[i], heightR[i]) - height[i];
            if (temp > 0) sum += temp;
        }
        return sum;
    }
}

class Solution2 {
    public int trap(int[] height) {
        int sum = 0;
        LinkedList stack = new LinkedList<>();
        stack.add(0);
        for (int i = 1; i < height.length; i++) {
            if (height[i] < height[stack.peek()]) stack.push(i);
            else if (height[i] == height[stack.peek()]) {
                stack.pop();
                stack.push(i);
            } else {
                while (!stack.isEmpty() && height[i] > height[stack.peek()]){
                    int mid = stack.pop();
                    if (!stack.isEmpty()){//这个地方要再判断一下,不然空指针
                        int left = stack.peek();
                        sum += (Math.min(height[left], height[i]) - height[mid]) * (i - left - 1);
                    }
                }
                stack.push(i);
            }
        }
        return sum;
    }
}

84.柱状图中最大的矩形

力扣题目链接

给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。

求在该柱状图中,能够勾勒出来的矩形的最大面积。

思路

  • 和上题思路类似

  • 但注意这题如果元素递增,会输出零,考虑使用数组扩容的方式,在头尾加上两个0,保证一定会取出面积

代码

class Solution {
    public int largestRectangleArea(int[] heights) {
        int res = 0;
        LinkedList stack = new LinkedList<>();
        int[] heightsNew = new int[heights.length + 2];
        for (int i = 1; i <= heights.length; i++) {
            heightsNew[i] = heights[i - 1];
        }
        stack.push(0);
        for (int i = 1; i < heightsNew.length; i++) {
            if (heightsNew[i] > heightsNew[stack.peek()]) stack.push(i);
            else if (heightsNew[i] == heightsNew[stack.peek()]) {
                stack.pop();
                stack.push(i);
            } else {
                while (!stack.isEmpty() && heightsNew[i] < heightsNew[stack.peek()]){
                    int mid = stack.pop();
                    if (!stack.isEmpty()){
                        int left = stack.peek();
                        res = Math.max(res, (i - left - 1) * heightsNew[mid]);
                    }
                }
                stack.push(i);
            }
        }
        return res;
    }
}

代码随想录一刷总结

  • 从一月底到现在,50天的时间,完成了代码随想录一刷

  • 除了个别比较难的题目,其他都自己手写了代码

  • 接下来要继续进行二刷,五一前争取二刷完毕!

  • 二刷目的是更熟悉题型,争取多写几种解法

  • 每天抽出来2h时间,限时完成

  • 慢慢算法路,才刚刚开始!

  • 加油吧!

  • 且视他人之疑目如盏盏鬼火,大胆地去走我的夜路。

你可能感兴趣的:(动态规划,数据结构,leetcode)