代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I

本文主要是介绍代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

代码随想录算法训练营第五十九天 | LeetCode 503. 下一个更大元素 II、42. 接雨水

文章链接:下一个更大元素 II、接雨水
视频链接:下一个更大元素 II、接雨水

1. LeetCode 503. 下一个更大元素 II

1.1 思路

  1. 本题是给一个数组求右边第一个比当前元素大的元素,好像和739. 每日温度差不多,但本题多了个循环数组的要求,首尾是相连的
  2. 思路 1:建立一个新数组,把原数组扩充一倍再放入这个新数组中,即这个新数组的长度是原数组的 2 倍,然后线性遍历求当前元素右边第一个比其大的元素,这样就不用循环数组了,最后返回一半数组即可。这么写就是空间复杂度就是创建了一个 2 倍的数组,时间复杂度就是 O(n)
  3. 思路 2:在原数组模拟循环的方式,通过取模的方式。遍历数组时还是通过 2 倍数组来遍历,for(int i=0;i<nums.length*2;i++),如果直接取 i,当超过 nums.length 时就会越界,因此 i=i%nums.length,这样当超出范围时一取模就又回来了。
  4. 单调栈的模板代码:result 数组存储结果,注意要将数组默认初始化为全-1 的值,因为本题找不到存的是-1,然后定义个栈,把 0 下标先放入 stack.push(0)。for(int i=1;i<nums.length*2;i++)从 1 开始是因为 0 下标已经存入。避免 i 越界,i=i%nums.length;if(nums[i]<=nums[stack.peek()])stack.push(i);else while(!stack.empty()&&nums[i]>nums[stack.peek()])result[stack.peek()]=nums[i],stack.pop();while 循环结束后 stack.push(i)。最终 return result。

1.2 代码

class Solution {public int[] nextGreaterElements(int[] nums) {//边界判断if(nums == null || nums.length <= 1) {return new int[]{-1};}int size = nums.length;int[] result = new int[size];//存放结果Arrays.fill(result,-1);//默认全部初始化为-1Stack<Integer> st= new Stack<>();//栈中存放的是nums中的元素下标for(int i = 0; i < 2*size; i++) {while(!st.empty() && nums[i % size] > nums[st.peek()]) {result[st.peek()] = nums[i % size];//更新resultst.pop();//弹出栈顶}st.push(i % size);}return result;}
}

2. LeetCode 42. 接雨水

2.1 思路

  1. 本题是给一个 height 数组“接雨水”,因为这些数组的元素形成柱子就会有一些凹槽,就能存些雨水,最后就返回能接多少岁雨水。
  2. 引出单调栈:单调栈适用于找到左边或者右边第一个比当前元素大的元素。本题的栈是递增还是递减呢?本题中我们不仅要求右边第一个比其大的元素,还要求左边第一个比其大的元素,因为要找到凹槽嘛,而我们确定一个凹槽就是要左右两边的柱子顶起来,中间有个底托起来
  3. 本题单调栈的工作过程是当前元素和栈顶元素比较,本题中如果当前元素大于栈顶元素那就是右边第一个比其大的元素,此时栈顶元素就是底了,右边的柱子也找到了,就差左边的柱子了,其实就在栈里,就是栈顶的下一个元素,这个就是左边第一个比其大的元素。
  4. 当前元素和栈顶元素的比较就大于等于小于三种情况。本题中,小于仍然是放入栈中;等于也是放入栈中,也可以把栈顶弹出再将但当前元素放入,其实都可以,但我们选择前者,这两个的区别就是计算有点差异而已;大于时,此时栈顶就是底,当前元素就是右边的柱子,左边的柱子就是栈顶下一个元素。
  5. 计算过程:底=stack.pop();柱子的高度要取最小值,因为取高的部分会漏出去,想象一下凹槽存水的原理木桶效应就知道了,h=Math.min(stack.peek(),height[i]),然后 h 减去 底的高度差就是存水的高度,凹槽的宽度就是右柱子的下标减去左柱子的下标,即 w=i-stack.peek()-1,为什么需要减 1,举例右柱子 4 下标,左柱子 2 下标,宽度应该是 1,求的就是中间凹槽的宽度,因此要-1。h*w 就是面积。因为栈顶前面弹出了,当前元素仍有可能比栈顶大,因此还能确定凹槽,因此用 while 循环遍历。前面说等于时是把当前元素直接放入还是先弹出再放入当前元素的时候,说的是都可以是因为,如果放入此时的最矮柱子和底的高度差是 0,面积也是 0,而如果弹出再放入就是少算了这个 0,因此没区别。
  6. 单调栈求面积是横向求的,而暴力是纵向求的。
  7. 代码实现:定义 sum 存面积,定义栈然后放入 0 下标,for(int i=1;i<height.length;i++)从 1 开始是因为 0 下标已经放入。if(height[i]<=height[stack.peek()])stack.push(i);else while(!stack.empty()&&heigth[i]>height[stack.peek()])int middle=stack.pop()这是底,if(!stack.empty())这里要判断一下不能为空栈,h=Math.min(height[stack.peek()],height[i])-height[mid] 这是高度差,w=i-stack.peek()-1 这是宽度;sum+=h*w。当 while 循环结束了也把当前元素放入栈中。最终 return sum。

2.2 代码

class Solution {public int trap(int[] height){int size = height.length;if (size <= 2) return 0;// in the stack, we push the index of array// using height[] to access the real heightStack<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]){// 因为相等的相邻墙,左边一个是不可能存放雨水的,所以pop左边的index, push当前的indexstack.pop();stack.push(index);}else{//pop up all lower valueint 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;}
}

这篇关于代码随想录算法训练营第五十九天 | LeetCode 739. 每日温度、496. 下一个更大元素 I的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/394978

相关文章

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Java集合之Iterator迭代器实现代码解析

《Java集合之Iterator迭代器实现代码解析》迭代器Iterator是Java集合框架中的一个核心接口,位于java.util包下,它定义了一种标准的元素访问机制,为各种集合类型提供了一种统一的... 目录一、什么是Iterator二、Iterator的核心方法三、基本使用示例四、Iterator的工

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

Vue实现路由守卫的示例代码

《Vue实现路由守卫的示例代码》Vue路由守卫是控制页面导航的钩子函数,主要用于鉴权、数据预加载等场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着... 目录一、概念二、类型三、实战一、概念路由守卫(Navigation Guards)本质上就是 在路

uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)

《uni-app小程序项目中实现前端图片压缩实现方式(附详细代码)》在uni-app开发中,文件上传和图片处理是很常见的需求,但也经常会遇到各种问题,下面:本文主要介绍uni-app小程序项目中实... 目录方式一:使用<canvas>实现图片压缩(推荐,兼容性好)示例代码(小程序平台):方式二:使用uni

JAVA实现Token自动续期机制的示例代码

《JAVA实现Token自动续期机制的示例代码》本文主要介绍了JAVA实现Token自动续期机制的示例代码,通过动态调整会话生命周期平衡安全性与用户体验,解决固定有效期Token带来的风险与不便,感兴... 目录1. 固定有效期Token的内在局限性2. 自动续期机制:兼顾安全与体验的解决方案3. 总结PS

C#中通过Response.Headers设置自定义参数的代码示例

《C#中通过Response.Headers设置自定义参数的代码示例》:本文主要介绍C#中通过Response.Headers设置自定义响应头的方法,涵盖基础添加、安全校验、生产实践及调试技巧,强... 目录一、基础设置方法1. 直接添加自定义头2. 批量设置模式二、高级配置技巧1. 安全校验机制2. 类型

Python屏幕抓取和录制的详细代码示例

《Python屏幕抓取和录制的详细代码示例》随着现代计算机性能的提高和网络速度的加快,越来越多的用户需要对他们的屏幕进行录制,:本文主要介绍Python屏幕抓取和录制的相关资料,需要的朋友可以参考... 目录一、常用 python 屏幕抓取库二、pyautogui 截屏示例三、mss 高性能截图四、Pill

使用MapStruct实现Java对象映射的示例代码

《使用MapStruct实现Java对象映射的示例代码》本文主要介绍了使用MapStruct实现Java对象映射的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录一、什么是 MapStruct?二、实战演练:三步集成 MapStruct第一步:添加 Mave