当前位置: 首页 > news >正文

使用单调栈解决力扣第42题--接雨水

1  单调栈

在解决这个问题前,我们先来了解一下,什么是单调栈

单调栈的概念比较简单,就是栈里面的元素要么是单调递增的,比如:1,3,5,7,9;要么是单调递减的,比如:9,6,5,4,3,2;要么是单调不增的,比如:9,9,6,6,3;要么是单调不降的,比如:1,1,2,3,3。

至于他是从栈顶到栈底,还是从栈底到栈顶,这个就不需要纠结了,而他的入栈与出栈和普通栈一样。

2  使用单调栈解决第一个问题-寻找一个数组中第i个元素前面比他大的第一个元素

假如说我们现在有一个数组为:9,2,8,5,4,6,7,现在我们要遍历整个数组,并且找到第i个元素左边比他大的第一个元素,比如第0个元素9,他的左边没有元素,所以他左边没有比他大的元素,所以对应的值一个为0(表示没有),再比如第5个元素6,他的左边有一个元素8比他大,所以他的返回值应该为3(因为0代表没有比他大的值,所以这里我们从1开始)。

那代码应该怎么写呢,容易想到的第一个算法应该就是暴力了吧,当我们循环到第i个元素时,再次循环第i-1~0个元素,找到一个比他大的值并且填充进去,代码可以这样写:

public class Baoli {public static void main(String[] args) {int[] array = { 2,1,4,2,1,1,3,3,2,2};System.out.println(Arrays.toString(baoli(array)));}public static int[] baoli(int[] list) {int[] result = new int[list.length];result[0] = 0;for (int i = 1; i < list.length; i++) {int big=0;for (int j = i-1; j >= 0; j--) {if (list[j] > list[i]) {big = j+1;break;}}result[i] = big;}return result;}
}

对于以上代码我们再做些优化,当然效果是一样的:

public static int[] baoli(int[] list) {int[] result = new int[list.length];result[0] = 0;int i = 1;int j = 0;while (i < list.length) {if(j==-1 || list[i]<list[j]) {result[i] = j+1;j=i++;}else j--;}return result;}

以上代码准确率毫无疑问是没有问题的,但从时间复杂复杂度方面考虑的话,他的时间复杂度为O(n^2),那有什么方法可以降低复杂段呢?

我们观察这组数据:9,2,8,5,4,6,7;如果我们找到了6这个元素所对应的值为8后,我们再去寻找7这个元素所对应的值时,我们观察方法,7是大于6的,而5与4皆小于6(因为查找6所对应的值时已经遍历过了他们两个),那我们可不可以跳过他们两个,直接去访问8这个元素呢?

这里我们可以引入一个栈来存放当前位置所对应的值的下标加一,因为我们还要考虑他左边没有比他更加大的值,所以初始化栈的时候,我们设栈顶指针为0,他所对应的栈顶元素为0,表示在左边已经没有比他更加大的值了,这个栈里面的元素是单调递增的,但数组所对应的栈元素是单调递减的,也就是说,当有一个元素比栈顶元素小时,我们就将这个元素所对应的下标+1入栈,当获取下一个元素时,就将元素直接与栈顶元素进行比较,如果栈顶元素比他大的话,说明这个元素所对应的值为当前栈顶元素所对应的值的索引位置,然后将该元素入栈;否则我们将栈顶元素抛出,然后继续比较,直到找到栈顶元素比它大或者栈顶元素为0,我们就将平方复杂度O(n^2)降低到了线性复杂度O(n),博主这里使用了一个数组模拟这个单调栈,可供大家进行参考:

public static int[] monotonicStack(int[] array) {int[] result = new int[array.length];  //处之后的数组int[] stack = new int[array.length]; //单调栈int top=0;stack[top] = 0;int i=1; //array的下标int k=0; //result的下标while (k < array.length) {if(top==0 || array[i-1]<array[stack[top]-1] ){result[k++] = stack[top];stack[++top]=i++;}else top--;}return result;}

这样一看,他的时间复杂度直接从O(n^2)降到了O(n)对于博主我这个初学者来说,简直是完美

3  使用单调栈解决力扣第42题--接雨水

接下来我们就用单调栈来处理这个问题吧

根据题目,我们可以先确定,如果说柱子的个数小于3的话,那么他一定接不到雨水,所以当数组的长度小于3时,我们直接返回0就行。

然后我们再根据单调栈的学习,循环每个值,找到在他左边和在他右边第一个比他大的值,但这时我们忽略了一个问题,如果说在他左边(或右边)比他大的值时,是不是就意味着能接更多的雨水,所以在这里我们还需要寻找在他左边(或右边)比他大的值的更左边(或更右边)是否有更大的值,然后用两边最大的值中取较小的那个值(桶能接多少水取决于最短的木板)减去当前柱子的长度就可以得出当前柱子所能接水的最大容量,然后依次相加就可以得出结论。

以下是博主写的代码,可供大家参考:

public class Test {public static void main(String[] args) {Scanner sc=new Scanner(System.in);String[] s=sc.nextLine().split(" ");int[] array =new int[s.length];for (int i = 0; i < s.length; i++) {array[i]=Integer.parseInt(s[i]);}System.out.println(trap(array));}public static int trap(int[] height) {if(height.length<3) return 0;int[] lList=lMax(height);int[] rList=rMax(height);int count = getCount(height, lList, rList);return count;}private static int getCount(int[] array, int[] lList, int[] rList) {int count = 0;for (int i = 0; i < array.length; i++) {if (lList[i] != 0 && rList[i] != 0) {int lMax = lList[i];int rMax = rList[i];while (lList[lMax - 1] != 0) {lMax = lList[lMax - 1];}while (rList[rMax - 1] != 0) {rMax = rList[rMax - 1];}count += Math.min(array[rMax - 1], array[lMax - 1]) - array[i];}}return count;}public static int[] lMax(int[] array) {int[] result = new int[array.length];  //处之后的数组int[] stack = new int[array.length+10]; //单调栈int top = 0;stack[top] = 0;int i = 1; //array的下标int k = 0; //result的下标while (k < array.length) {if (top == 0 || array[i - 1] < array[stack[top] - 1]) {result[k++] = stack[top];stack[++top] = i++;} else top--;}return result;}public static int[] rMax(int[] array) {int[] result = new int[array.length];  //处之后的数组int[] stack = new int[array.length+10]; //单调栈int top = 0;stack[top] = 0;int i = array.length; //array的下标int k = array.length - 1; //result的下标while (k > -1) {if (top == 0 || array[i - 1] < array[stack[top] - 1]) {result[k--] = stack[top];stack[++top] = i--;} else top--;}return result;}
}

虽然说过程充满了坎坷,但数据总算全部通过了,啊!又是天才的一天。

http://www.dtcms.com/a/324923.html

相关文章:

  • 亚麻云之静态资源管家——S3存储服务实战
  • SSH远程连接TRAE时显示权限被拒绝检查方案
  • 游泳学习 — 蛙泳
  • 变量详解:创建初始化与内存管理
  • go加速配置(下载第三方库)
  • go语言运算符
  • Java变量的声明规则与Scanner的应用
  • 算法训练营day44 动态规划⑪ 1143.最长公共子序列、1035.不相交的线、53. 最大子序和、392.判断子序列
  • BGP实验
  • (三)全栈(部署)
  • 数学建模——回归分析
  • 解决 Linux 下 “E: 仓库xxx没有数字签名” 问题
  • C++高频知识点(十九)
  • CentOS7.9 离线安装mysql数据库
  • Python vs MATLAB:智能体开发实战对比
  • 安卓录音方法
  • Python描述符进阶:自定义文档与属性删除的艺术
  • 可视化程序设计(4) - 第一个图形窗口程序
  • 从 GPT‑2 到 gpt‑oss:解析架构的迭代
  • BandiView:高效多功能的图像查看和管理工具
  • 系统调用sigaction的工作流程
  • 算法训练之队列和优先级队列
  • Ubuntu 24.04 适配联发科 mt7902 pcie wifi 网卡驱动实践
  • MySQL的存储引擎:
  • C/C++内存管理函数模板
  • Flutter开发 页面间的值传递示例
  • 基于C语言(兼容C++17编译器)的记账系统实现
  • 虚拟机安装 爱快ikuai 软路由 浏览器无法访问/拒绝连接
  • 数据库面试题集
  • Effective C++ 条款34:区分接口继承和实现继承