单调栈
灵茶山艾府
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。
单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是整个数组只需要遍历一次。
单调栈的作用:记录遍历过的元素,与当前元素做对比。当前遍历元素和栈口元素做对比。
- 使用单调栈主要有三个判断条件。
当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
739. 每日温度
暴力法
我的答案,写错了
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] answer = new int[temperatures.length];
if(temperatures.length == 1) return answer;
Arrays.fill(answer, Integer.MAX_VALUE);
for(int i=0; i<temperatures.length-1; i++) {
int flag = 0;
int j=i+1;
while(j<temperatures.length && answer[j]>answer[i]) {
flag++;
j++;
}
answer[i] = flag;
}
return answer;
}
}
单调栈
求当前元素右边第一个比它大的/小的 元素
单调栈的作用:记录遍历过的元素,与当前元素做对比。当前遍历元素和栈口元素做对比
这个单调栈要是递增的。
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
Stack<Integer> st = new Stack<Integer>();
st.push(0);
int[] answer = new int[temperatures.length];
for(int i=1; i<temperatures.length; i++) {
if(temperatures[i] <= temperatures[st.peek()]) {
st.push(i);
}
else {
while(!st.empty() && temperatures[i] > temperatures[st.peek()]) {
int index = st.pop();
answer[index] = i - index;
}
st.push(i);
}
}
return answer;
}
}
- 出错点在要牢记栈保存的是数组的下标而不是值
更好理解的单调栈版本
从后往前遍历:及时去掉无用数据,保证栈中数据有序。
比栈顶元素小就入栈,否则栈顶弹出。
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int n = temperatures.length;
int[] ans = new int[n];
Deque<Integer> st = new ArrayDeque<>();
for (int i = n - 1; i >= 0; i--) {
int t = temperatures[i];
while (!st.isEmpty() && t >= temperatures[st.peek()]) {
st.pop();
}
if (!st.isEmpty()) {
ans[i] = st.peek() - i;
}
st.push(i);
}
return ans;
}
}
- while必须是大于等于
496.下一个更大元素 I
- 需要加一个hashmap来快速映射nums1中的元素
- Arrays.fill(ans, -1);
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
//单调栈的数组下标
Stack<Integer> st = new Stack<Integer>();
//MAP
HashMap<Integer, Integer> hashMap = new HashMap<>();
int[] ans = new int[nums1.length];
Arrays.fill(ans, -1);
for(int i=0; i<nums1.length; i++) {
hashMap.put(nums1[i],i);
}
for(int i=nums2.length-1; i>=0; i--) {
int tmp = nums2[i];
while(!st.empty() && tmp>=st.peek()) {
st.pop();
}
//处理完之后栈顶元素要么为空 要么比nums[i]大
if(!st.empty()) {
if(hashMap.containsKey(tmp)){
ans[hashMap.get(tmp)] = st.peek();
}
}
st.push(tmp);
}
return ans;
}
}
503.下一个更大元素II
将两个nums数组拼接在一起,使用单调栈计算出每一个元素的下一个最大值,最后再把结果集即result数组resize到原数组大小就可以了。
class Solution {
public int[] nextGreaterElements(int[] nums) {
Stack<Integer> st = new Stack<>();
int len = nums.length;
int[]ans = new int[len];
Arrays.fill(ans, -1);
for(int i=2*len-1; i>=0; i--) {
int x = nums[i % len];
while(!st.empty() && x >= st.peek()) {
st.pop();
}
if(i<len && !st.empty()) {
ans[i] = st.peek();
}
st.push(x);
}
return ans;
}
}
if(i<len)