力扣刷题day50|739每日温度、496下一个更大元素 I
创始人
2024-01-29 01:33:58
0

文章目录

    • 739. 每日温度
      • 暴力思路
      • 单调栈思路
        • 什么时候用单调栈?
        • 解题思路
    • 496. 下一个更大元素 I
      • 思路
        • 单调栈

739. 每日温度

力扣题目链接

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

暴力思路

暴力解法,两层for循环,第一个for循环每个天数,第二个for找该天温度后面的更高温

单调栈思路

什么时候用单调栈?

  • 怎么能想到用单调栈呢? 什么时候用单调栈呢?

通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了

例如本题其实就是要找到一个元素右边第一个比自己大的元素

  • 那么单调栈的原理是什么呢?为什么**时间复杂度是O(n)**就可以找到每一个元素的右边第一个比它大的元素位置呢?

单调栈的本质是空间换时间,因为在遍历的过程中需要用一个栈来记录右边第一个比当前元素高的元素,优点是只需要遍历一次。

  • 在使用单调栈的时候首先要明确如下几点:
  1. 单调栈里存放的元素是什么?

单调栈里**只需要存放元素的下标i**就可以了,如果需要使用对应的元素,直接T[i]就可以获取。

  1. 单调栈里元素是递增呢? 还是递减呢?

注意一下顺序为从栈顶到栈底的顺序(因为说从左到右或者从前到后,不知道栈顶和栈底是哪)

这道题中,从栈顶到栈底的顺序是递增循序,因为只有递增的时候,加入一个元素i,才知道栈顶元素在数组中右面第一个比栈顶元素大的元素是i

解题思路

使用单调栈主要有个判断条件。

  • 当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况
  • 当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况

用示例1的temperatures = [73, 74, 75, 71, 71, 72, 76, 73]为例来逐步分析,输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]来画图解题

首先先将第一个遍历元素下标加入单调栈

image-20221117151722971

加入T[1] = 74,因为T[1] > T[0](当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),而我们要保持一个递增单调栈(从栈顶到栈底),所以将T[0]弹出,T[1]加入,此时result数组可以记录了,result[0] = 1,即T[0]右面第一个比T[0]大的元素是T[1]

image-20221117152150710

加入T[2],同理,T[1]弹出

image-20221117152403372

加入T[3]T[3] < T[2] (当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况),加T[3]加入单调栈。

image-20221117152656426

加入T[4]T[4] == T[3] (当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况),此时依然要加入栈,不用计算距离,因为我们要求的是右面第一个大于本元素的位置,而不是大于等于!

image-20221117153058307

加入T[5]T[5] > T[4] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[4]弹出,同时计算距离,更新result

image-20221117153403827

T[4]弹出之后, T[5] > T[3] (当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况),将T[3]继续弹出,同时计算距离,更新result

image-20221117153752683

直到发现T[5]小于T[st.top()],终止弹出,将T[5]加入单调栈

image-20221117153851023

加入T[6],同理,需要将栈里的T[5]弹出

image-20221117154324239

继续弹出T[2]

image-20221117154449416

此时栈里只剩下了T[6]

image-20221117154556870

加入T[7]T[7] < T[6]直接入栈,这就是最后的情况,result数组也更新完了。

image-20221117154725221

result[6] result[7]初始化的时候就为0(如果result没有更新,说明这个元素右面没有更大的了,也就是为0)

完整代码:

public int[] dailyTemperatures(int[] temperatures) {int[] res = new int[temperatures.length];// 定义单调栈Deque stack = new LinkedList<>();// 空栈直接入栈stack.push(0);// 遍历每个温度for (int i = 1; i < temperatures.length; 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;
}

注:想把LinkedList当做集合list,那么应该用add/remove,如果想用作队列,则使用offer/poll,如果用作栈,则使用push/pop,如果用作双端队列,则使用offerFirst/offerLast/pollFirst/pollLast。根据语义使用,就不会发生:我想删队尾,结果删了队头这种事了。

496. 下一个更大元素 I

力扣题目链接

nums1 中数字 x下一个更大元素 是指 xnums2 中对应位置 右侧第一个x 大的元素。

给你两个 没有重复元素 的数组 nums1nums2 ,下标从 0 开始计数,其中nums1nums2 的子集。

对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j]下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1

返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素

示例 1:

输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
- 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
- 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。

示例 2:

输入:nums1 = [2,4], nums2 = [1,2,3,4].
输出:[3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:
- 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
- 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。

思路

由题意可以指导要定义一个和nums1一样大小的数组result来存放结果。

  • 这个result数组初始化应该为多少呢?

题目说如果不存在对应位置就输出 -1 ,所以result数组如果某位置没有被赋值,那么就应该是是-1,所以就初始化为-1。

在遍历nums2的过程中,我们要判断nums2[i]是否在nums1中出现过,因为最后是要根据nums1元素的下标来更新result数组。

注意题目中说是两个没有重复元素 的数组 nums1 和 nums2

没有重复元素,我们就可以用map来做映射了。根据数值快速找到下标,还可以判断nums2[i]是否在nums1中出现过。

// 把nums1装入map
HashMap hashMap = new HashMap<>();
for (int i = 0 ; i< nums1.length ; i++){hashMap.put(nums1[i],i);
}

单调栈

  • 为什么要用单调栈呢?因为我们要找nums1中元素的右边第一个更大的元素,而nums1中的元素都是存在于nums2中的。
  • 所以当我们发现nums2中的某个元素是大于前面元素的时候时,就判断这个元素是不是同样存在于nums1中,如果在nums1中,那就可以记录下当前的大元素到结果数组中

使用单调栈,首先要想单调栈是从大到小还是从小到大。

栈头到栈底的顺序,要从小到大,也就是保持栈里的元素为递增顺序。只要保持递增,才能找到右边第一个比自己大的元素。

接下来就要分析如下种情况,将nums2的元素入栈

  1. 情况一:当前遍历的元素T[i]小于栈顶元素T[st.top()]的情况

此时满足递增栈(栈头到栈底的顺序),所以直接入栈。

  1. 情况二:当前遍历的元素T[i]等于栈顶元素T[st.top()]的情况

如果相等的话,依然直接入栈,因为我们要求的是右边第一个比自己大的元素,而不是大于等于!

  1. 情况三:当前遍历的元素T[i]大于栈顶元素T[st.top()]的情况

此时如果入栈就不满足递增栈了,这也是找到右边第一个比自己大的元素的时候。

判断栈顶元素是否在nums1里出现过,(注意栈里的元素是nums2的元素),如果出现过,开始记录结果。

记录结果的逻辑是:此时栈顶元素在nums2中右面第一个大的元素是nums2[i]当前遍历元素

完整代码

public int[] nextGreaterElement(int[] nums1, int[] nums2) {int[] res = new int[nums1.length];Arrays.fill(res, -1);// 把nums1装入map  key:下标元素,value:下标HashMap map = new HashMap<>();for (int i = 0 ; i < nums1.length ; i++){map.put(nums1[i], i);}// 定义单调栈Deque stack = new LinkedList<>();stack.push(0);for (int i = 1; i < nums2.length; i++) {if (nums2[i] <= nums2[stack.peek()]) {stack.push(i);}else {while (!stack.isEmpty() && nums2[i] > nums2[stack.peek()]) {// 看nums1里是否存在这个元素if (map.containsKey(nums2[stack.peek()])) {// 根据map找到nums2[stack.peek()] 在 nums1中的下标int index = map.get(nums2[stack.peek()]);res[index] = nums2[i];}stack.pop();}stack.push(i);}}return res;
}

相关内容

热门资讯

“在美生意已无利可图” 塞尔维...   美国总统特朗普近期表示,将从8月1日起对塞尔维亚的进口产品征收35%的关税。这让塞尔维亚出口企业...
“万众一心”的热血战歌如何响彻...   原上海公共体育场中央,指挥家刘良模站在高凳上,指挥民众合唱《义勇军进行曲》等救亡歌曲……7月4日...
河南,真中!   当清晨的阳光  唤醒沉睡的古都  奔涌不息的河水  奏起雄浑的乐章  广袤的中原大地  焕发出勃...
凡人微光|“撑”起一片天   策划:卓越  统筹:郭依格、崔莺馨  制作:徐兰  出品:新华社新媒体中心、快手
石榴花开 籽籽同心丨从“爆红”...   悠远的天空,洁白的云朵,远处起伏的山峦,草场上一颗高大的树木,一个经历过风霜的木牌上写着“彩虹布...
让更多人走进赛场、体验“十五运...   第十五届全国运动会8月1日将迎来开幕式倒计时100天。7月25日,国务院新闻办举行新闻发布会,介...
​现金流量套期与公允价值套期会... 现金流量套期与公允价值套期会计处理有何区别公允价值套期和现金流量套期的区别主要体现在套期对象、目的和...
保民生、促消费,财政政策有力度... 数据来源:国家发展改革委、财政部  7月25日,财政部召开2025年上半年财政收支情况新闻发布会。 ...
扎根国防一线30年 导弹筑巢...   火箭军某旅工程安装技师崔道虎,矢志建功国防工程30年,先后在8个工种、12个岗位历练,参与30余...
中新健康丨五个关键词,读懂“十...   中新网北京7月24日电(记者 张尼)基本医疗保险参保率稳定在95%左右,医保码、移动支付和电子处...