文章目录
- 前言
- 一、今天学习了什么?
- 二、算法----》单调栈
- 1、介绍
- 2、题目
- 总结
前言
提示:这里为每天自己的学习内容心情总结;
Learn By Doing,Now or Never,Writing is organized thinking.
今天拿到了上周面试的结果,说我基础不错以为能进,结果名额不够了。
有点焦虑,努力吧,秋招才刚开始呢。
提示:以下是本篇文章正文内容
一、今天学习了什么?
- 写完了代码随想录的单调栈部分的算法题;
- 其它的没做;
二、算法----》单调栈
1、介绍
如果要在一维数组中,寻找任意一个元素的右边或者是左边第一个比自己大或者小的元素的位置,可以采用「单调栈」,时间复杂度为O(N)。
利用一个栈记录在遍历过程中记录遍历过的元素,重点:
- 单调栈内只需要存放元素的下标即可;
- 单调栈内的顺序(顺序是指栈头到栈底),分为:
- 如果求一个元素右边第一个更大元素,单调栈就是递增的;
- 如果求一个元素右边第一个更小元素,单调栈就是递减的。
用 temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

2、题目
- 739. 每日温度;(⭐⭐⭐⭐⭐)
public int[] dailyTemperatures(int[] temperatures) {/*** - 采用一个单调栈进行遍历数据* - 每次都需要找到当前元素的右边第一个更大的元素* - 栈底到栈尾存放元素应该是由大到小* - 比较栈顶元素和即将入栈元素的大小:* - 当栈顶元素温度小于即将入栈元素的温度时,弹出栈顶元素并设置结果集* - 重复弹出,直至栈为空或者栈顶元素大于入站元素*/Stack<Integer> stack = new Stack<>();stack.push(0);int[] result = new int[temperatures.length];for (int i = 1; i < temperatures.length; i++) {while (!stack.isEmpty() && temperatures[stack.peek()] < temperatures[i]) {Integer pop = stack.pop();result[pop] = i - pop;}stack.push(i);}return result;}
- 496. 下一个更大元素 I;
public int[] nextGreaterElement(int[] nums1, int[] nums2) {/*** - 还是使用单调栈,存储在nums2数组中,找到比当前元素大的元素下标* - 利用一个map维持映射关系 key是nums2的元素值,value是nums2的元素下标* - result保存的是nums2中当前元素的下一个更大元素的下标*/Map<Integer, Integer> map = new HashMap<>();Stack<Integer> stack = new Stack<>();int[] result = new int[nums2.length];Arrays.fill(result, -1);for (int i = 0; i < nums2.length; i++) {while (!stack.isEmpty() && nums2[i] > nums2[stack.peek()]) {Integer pop = stack.pop();result[pop] = i;}stack.push(i);map.put(nums2[i], i);}int[] ans = new int[nums1.length];for (int i = 0; i < nums1.length; i++) {int index = result[map.get(nums1[i])];if (index == -1) {ans[i] = -1;} else {ans[i] = nums2[index];}}return ans;}
- 503. 下一个更大元素 II;
public int[] nextGreaterElements(int[] nums) {/*** - 还是采用栈结构,由于是一个循环数组,所以需要遍历数组中的元素次数多一点*/int length = nums.length;int[] ans = new int[length];Arrays.fill(ans, -1);Stack<Integer> stack = new Stack<>();for (int i = 0; i < 2 * length; i++) {while (!stack.isEmpty() && nums[i % length] > nums[stack.peek()]) {Integer pop = stack.pop();ans[pop] = nums[i % length];}stack.push(i % length);}return ans;}
- 42. 接雨水;(⭐⭐⭐⭐⭐)
// 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。/**height: 数组,柱子高度*/public int trap(int[] height) {// base caseint length = height.length;if(length <= 2){return 0;}// 定义一些变量int sum = 0;// 最后接的雨水值// 单调栈,栈顶到栈底是,按照元素值从小到大,但是存储的是数组中元素下标Stack<Integer> stack = new Stack<>();stack.push(0);for(int i = 1; i < length; i++){// 栈中是一定存在元素的int stackTopIndex = stack.peek();// 栈顶中元素对应在height数组中的下标// 如果新加入的元素,比栈顶的元素小,直接压入栈中if(height[i] < height[stackTopIndex]){stack.push(i);}else if(height[i] == height[stackTopIndex]){// 如果新加入的元素,和栈顶的元素值相同,弹出栈顶元素,并且将新元素加入栈中stack.pop();stack.push(i);}else{// 情况三:要压入栈中的元素值,大于栈顶的元素值int top = stack.peek();// 遍历每一个比即将压入栈中小的元素while(!stack.isEmpty() && height[i] > height[top]){int cur = stack.pop();// 当前元素为高度// 算雨水量是根据宽度*高度if(!stack.isEmpty()){int left = stack.peek();int h = Math.min(height[left], height[i]) - height[cur];int w = i - left - 1;int res = h * w;sum += res;top = stack.peek();}}stack.push(i);}}return sum;}
- 84. 柱状图中最大的矩形;
public int largestRectangleArea(int[] heights) {/*** - 采用单调栈,栈里存储元素下标* - 栈底到栈顶的元素是从小到大* - 遍历数组中的元素和栈顶相比,只有当即将入栈的元素小于栈顶元素时,需要计算矩形的面积* - 需要重新设置数组元素*/int[] arr = new int[heights.length + 2];for (int i = 0; i < heights.length; i++) {arr[i + 1] = heights[i];}int ans = 0;Stack<Integer> stack = new Stack<>();stack.push(0);for (int i = 1; i < arr.length; i++) {int peek = stack.peek();if (arr[i] > arr[peek]) {stack.push(i);} else if (arr[i] == arr[peek]) {stack.pop();stack.push(i);} else {while (!stack.isEmpty() && arr[i] < arr[peek]) {peek = stack.pop();int mid = arr[peek];peek = stack.peek();int width = i - peek - 1;ans = Math.max(ans, mid * width);}stack.push(i);}}return ans;}
总结
提示:这里对文章进行总结:
记住单调栈用的场景,求数组中离该元素最近的最小或者最大的元素。
遍历数组元素的时候,按照从小到大或者从大到小的顺序添加元素,注意情况的比较和出入栈的时机。