单调栈 单调栈的使用场景:
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置。主要用于解决滑动窗口 问题。
单调栈的本质是空间换时间 ,因为在遍历的过程中需要用一个栈 来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
739.每日温度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 class Solution { public int [] dailyTemperatures(int [] temperatures) { int lens=temperatures.length; int []res = new int [lens]; Deque<Integer> stack = new LinkedList <>(); stack.push(0 ); for (int i = 1 ; i < lens ;i++){ if (temperatures[i] <= temperatures[stack.peek()]){ stack.push(i); }else { while (!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]){ res[stack.peek()] = i-stack.peek(); stack.pop(); } stack.push(i); } } return res; } }
496.下一个更大元素Ⅰ
单调栈,栈里存的是数组下标 ,和739.每日温度相同思路
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution { public int [] nextGreaterElement(int [] nums1, int [] nums2) { int len1 = nums1.length; int len2 = nums2.length; int [] resA = new int [len1]; int [] resB = new int [len2]; Deque<Integer> stack = new LinkedList <>(); stack.push(resB[0 ]); for (int i = 1 ;i < len2; i++){ if (nums2[i] <= nums2[stack.peek()]){ stack.push(i); }else { while (!stack.isEmpty() && nums2[i] > nums2[stack.peek()]){ resB[stack.peek()] = i-stack.peek(); stack.pop(); } stack.push(i); } } for (int i = 0 ;i < len1; i ++){ for (int j = 0 ;j < len2; j ++){ if (nums1[i] == nums2[j]){ resA[i] = resB[j] == 0 ? -1 : nums2[j + resB[j]]; } } } return resA; } }
503.下一个更大元素Ⅱ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution { public int [] nextGreaterElements(int [] nums) { int len = nums.length; int [] res = new int [len]; int [] numsCopy = new int [len * 2 ]; int [] resCopy = new int [len * 2 ]; for (int i = 0 ; i < len ;i ++){ numsCopy[i] = nums[i]; numsCopy[i + len] = nums[i]; } Deque<Integer> stack = new LinkedList <Integer>(); stack.push(0 ); for (int i = 0 ;i < len * 2 ; i ++){ if (numsCopy[i] <= numsCopy[stack.peek()]){ stack.push(i); }else { while (stack.peek() != null && numsCopy[i] > numsCopy[stack.peek()]){ resCopy[stack.peek()] = i - stack.peek(); stack.pop(); } stack.push(i); } } for (int i = 0 ; i < len ; i ++){ res[i] = resCopy[i] == 0 ? -1 : numsCopy[i + resCopy[i]]; } return res; } }
42.接雨水
想清楚怎么接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Solution { public int trap (int [] height) { int size = height.length; if (size <= 2 ) return 0 ; Stack<Integer> stack = new Stack <Integer>(); stack.push(0 ); int sum = 0 ; for (int index = 1 ; index < size; index++){ int stackTop = stack.peek(); if (height[index] < height[stackTop]){ stack.push(index); }else if (height[index] == height[stackTop]){ stack.pop(); stack.push(index); }else { int heightAtIdx = height[index]; while (!stack.isEmpty() && (heightAtIdx > height[stackTop])){ int mid = stack.pop(); if (!stack.isEmpty()){ int left = stack.peek(); int h = Math.min(height[left], height[index]) - height[mid]; int w = index - left - 1 ; int hold = h * w; if (hold > 0 ) sum += hold; stackTop = stack.peek(); } } stack.push(index); } } return sum; } }
84.柱状图中最大矩形
和接雨水相反的操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /** 最大面积受限于高和宽 因此这里用单调栈来做,但是栈顶是最大值 。 栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度 */ class Solution { int largestRectangleArea(int[] heights) { Stack<Integer> st = new Stack<Integer>(); // 数组扩容,在头和尾各加入一个元素 int [] newHeights = new int[heights.length + 2]; newHeights[0] = 0; newHeights[newHeights.length - 1] = 0; for (int index = 0; index < heights.length; index++){ newHeights[index + 1] = heights[index]; } heights = newHeights; st.push(0); int result = 0; // 第一个元素已经入栈,从下标1开始 for (int i = 1; i < heights.length; i++) { // 注意heights[i] 是和heights[st.top()] 比较 ,st.top()是下标 if (heights[i] > heights[st.peek()]) { st.push(i); } else if (heights[i] == heights[st.peek()]) { st.pop(); st.push(i); } else { while (heights[i] < heights[st.peek()]) { // 注意是while int mid = st.peek(); st.pop(); int left = st.peek(); int right = i; int w = right - left - 1; int h = heights[mid]; result = Math.max(result, w * h); } st.push(i); } } return result; } }