之前做的239.滑动窗口也是单调栈问题,为了更好的理解单调栈,引用一个故事,如下:
要自己构造单调队列,看到了力扣上讨论@虫子的世界,讲了一个单调队列的故事,非常形象。单调队列真是一种让人感到五味杂陈的数据结构,它的维护过程更是如此.....就拿此题来说,队头最大,往队尾方向单调......有机会站在队头的老大永远心狠手辣,当它从队尾杀进去的时候,如果它发现这里面没一个够自己打的,它会毫无人性地屠城,把原先队里的人头全部丢出去,转身建立起自己的政权,野心勃勃地准备开创一个新的王朝.....这时候,它的人格竟发生了一百八十度大反转,它变成了一位胸怀宽广的慈父!它热情地请那些新来的“小个子”们入住自己的王国......然而,这些小个子似乎天性都是一样的——嫉妒心强,倘若见到比自己还小的居然更早入住王国,它们会心狠手辣地找一个夜晚把它们通通干掉,好让自己享受更大的“蛋糕”;当然,遇到比自己强大的,它们也没辙,乖乖夹起尾巴做人。像这样的暗杀事件每天都在上演,虽然王国里日益笼罩上白色恐怖,但是好在没有后来者强大到足以干翻国王,江山还算能稳住。直到有一天,闯进来了一位真正厉害的角色,就像当年打江山的国王一样,手段狠辣,野心膨胀,于是又是大屠城......历史总是轮回的。
739.每日温度
文章链接:代码随想录 (programmercarl.com)
思路:采用暴力的解法,提交时发现有一个例子通不过
看完文章后的反思:利用单调栈,且栈中存放的是下标
(1)何时使用单调栈
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了!!!
(2)在使用单调栈的时候首先要明确如下几点:
a. 单调栈里存放的元素是什么?
单调栈里只需要存放元素的下标i就可以了,如果需要使用对应的元素,直接T[i]就可以获取。
b. 单调栈里元素是递增呢? 还是递减呢?
此题应该是单调递增,因为这样才能够判断下一个比当前元素温度高的位置在哪儿
Java代码(暴力解法):leecode最后一个例子通过不了,其余都可以,说明本题暴力解法不是最优解
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] res = new int[temperatures.length];
if(temperatures.length == 0 || temperatures == null){
return res;
}
Arrays.fill(res,0);
for(int i = 0; i < temperatures.length;i++){
for(int j = i + 1;j < temperatures.length;j++){
if(temperatures[i] < temperatures[j]){
res[i] = j - i;
break;
}
}
}
return res;
}
}
Java代码:(单调栈)
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int lens=temperatures.length;
int []res=new int[lens];
Deque<Integer> stack=new LinkedList<>();
for(int i=0;i<lens;i++){
while(!stack.isEmpty()&&temperatures[i]>temperatures[stack.peek()]){
res[stack.peek()]=i-stack.peek();
stack.pop();
}
stack.push(i);
}
return res;
}
}
496.下一个更大元素|
文章链接:代码随想录 (programmercarl.com)
思路:无思路
看完文章后的反思:利用单调栈,且栈中存放的是下标
(1)没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过
(2)单调栈应该保持单调递增(从栈顶到栈底)
(3)接下来就要分析如下三种情况,一定要分析清楚。
a. 情况一:当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
此时满足递增栈(栈头到栈底的顺序),所以直接入栈。
b. 情况二:当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
如果相等的话,依然直接入栈,因为我们要求的是右边第一个比自己大的元素,而不是大于等于!
c. 情况三:当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况
此时如果入栈就不满足递增栈了,这也是找到右边第一个比自己大的元素的时候。
判断栈顶元素是否在nums1里出现过,(注意栈里的元素是nums2的元素),如果出现过,开始记录结果。
Java代码:使用单调栈
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
Stack<Integer> temp = new Stack<>();
int[] res = new int[nums1.length];
Arrays.fill(res,-1);
HashMap<Integer, Integer> hashMap = new HashMap<>();
for (int i = 0 ; i< nums1.length ; i++){
hashMap.put(nums1[i],i);
}
temp.add(0);
for (int i = 1; i < nums2.length; i++) {
if (nums2[i] <= nums2[temp.peek()]) {
temp.add(i);
} else {
while (!temp.isEmpty() && nums2[temp.peek()] < nums2[i]) {
if (hashMap.containsKey(nums2[temp.peek()])){
Integer index = hashMap.get(nums2[temp.peek()]);
res[index] = nums2[i];
}
temp.pop();
}
temp.add(i);
}
}
return res;
}
}
Java代码:使用暴力求解的方法
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
//使用暴力解法
int[] res = new int[nums1.length];
//初始化
Arrays.fill(res,-1);
//用m来记录nums1的元素在nums2中出现的位置下标
int m = 0;
for(int i = 0 ; i < nums1.length;i++){
//先找nums1的元素在nums2中出现的位置下标
for(int j = 0; j < nums2.length;j++){
if(nums1[i] == nums2[j]){
m = j;
}
}
//再进行遍历,找到下一个更大元素
for(int k = m + 1; k < nums2.length;k++){
if(nums1[i] < nums2[k]){
res[i] = nums2[k];
break;
}
}
}
return res;
}
}