每日温度 LeetCode 739
题目链接:[LeetCode 739 - 中等]
思路
什么时候使用单调栈:
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了
使用单调栈主要有三个判断条件。
- 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
- 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
- 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
将以上三种情况分析清楚后再进行代码的编写
单调栈:
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int len = temperatures.length;
int[] answer = new int[len];
Deque<Integer> st = new LinkedList<>();
st.push(0);
for(int i=1;i<len;i++){
while(!st.isEmpty()&&temperatures[i]>temperatures[st.peek()]){
answer[st.peek()]=i-st.peek();
st.pop();
}
st.push(i);
}
return answer;
}
}
下一个更大元素 I LeetCode 496
题目链接:[LeetCode 496 - 简单]
思路
原先的想法就是保持#739中的思路,先创建一个ans数组的协助数组,里面中存储num2中第一个比下标大的数的下标,然后通过两个for循环来帮助ans找到对应的数值
实际上可以使用map。代码更加简洁高效。
单调栈:
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int[] ans = new int[len1];
int[] ansH = new int[len2];
Deque<Integer> st = new LinkedList<>();
st.push(0);
for(int i=1;i<len2;i++){
while(!st.isEmpty()&&nums2[i]>nums2[st.peek()]){
ansH[st.pop()]=i;
}
st.push(i);
}
for(int i=0;i<len1;i++){
for(int j=0;j<len2;j++){
if(nums1[i]==nums2[j]){
ans[i]=(ansH[j]==0)?-1:nums2[ansH[j]];
}
}
}
return ans;
}
}
优化版本(使用Map)
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int len1 = nums1.length;
Map<Integer,Integer> map = new HashMap<>();
for(int i=0;i<len1;i++){
map.put(nums1[i],i);
}
int len2 = nums2.length;
int[] ans = new int[len1];
Arrays.fill(ans,-1);
Deque<Integer> st = new LinkedList<>();
for(int i=0;i<len2;i++){
while(!st.isEmpty()&&nums2[i]>nums2[st.peek()]){
int pre = nums2[st.poll()];
if(map.containsKey(pre)){
ans[map.get(pre)]=nums2[i];
}
}
st.push(i);
}
return ans;
}
}
下一个更大元素 II LeetCode 503
题目链接:[LeetCode 503 - 中等]
思路
基本思路与#739一致,但是需要加上%len
单调栈:
class Solution {
public int[] nextGreaterElements(int[] nums) {
int len = nums.length;
Deque<Integer> st = new LinkedList<>();
int[] ans = new int[len];
Arrays.fill(ans,-1);
st.push(0);
for(int i=1;i<len*2;i++){
while(!st.isEmpty()&&nums[i%len]>nums[st.peek()]){
ans[st.peek()]=nums[i%len];
st.poll();
}
st.push(i%len);
}
return ans;
}
}
接雨水 LeetCode 42
题目链接:[LeetCode 42 - 困难]
思路
手撕常见题 比较困难,需要多做几次。
单调栈:
class Solution {
public int trap(int[] height) {
int size = height.length;
if(size <= 2)return 0;
int sum = 0;
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 1; i < size; i++){
int stackTop = stack.peek();
if(height[i] < height[stackTop]){
stack.push(i);
}else if(height[i] == height[stackTop]){
stack.pop();
stack.push(i);
}else{
int highHeigth = height[i];
while(!stack.isEmpty()&&highHeigth>height[stackTop]){
int mid = stack.pop();
if(!stack.isEmpty()){
int left = height[stack.peek()];
int h = Math.min(highHeigth,left) - height[mid];
int w = i - stack.peek() - 1;
int area = h * w;
if(area > 0) sum += area;
stackTop = stack.peek();
}
}
stack.push(i);
}
}
return sum;
}
}
柱状图中最大的矩形 LeetCode 84
题目链接:[LeetCode 84 - 中等]
思路
1.具体思路与接雨水一致
2.但是有一点 w的时候,需要int left = stack.peek();int w = i - left - 1;来计算。
动态规划:
class Solution {
public int largestRectangleArea(int[] heights) {
int area = 0;
int[] newHeight = new int[heights.length + 2];
System.arraycopy(heights, 0, newHeight, 1, heights.length);
newHeight[heights.length+1] = 0;
newHeight[0] = 0;
int len = newHeight.length;
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 1; i < len; i++ ){
while(!stack.isEmpty()&&newHeight[i]<newHeight[stack.peek()]){
int mid = stack.pop();
int h = newHeight[mid];
int left = stack.peek();
int w = i - left - 1;
area = Math.max(h*w,area);
}
stack.push(i);
}
return area;
}
}