Day51 算法记录| 动态规划 18(单调栈)

news2024/11/24 20:40:06

单调栈

  • 739. 每日温度
  • 496.下一个更大元素 I
  • 503. 下一个更大元素 II
  • 42. 接雨水
  • 84. 柱状图中最大的矩形

单调栈:找最近的比他大的值
最近大的值:需要一个单调递减的栈(大于栈顶元素就弹出)
最近最小值:单调递减栈

方向: 右边,从后往前遍历 左边:从头遍历

739. 每日温度

单调栈:找最近的比他大的值
我最开始也是两层for循环,严重超时
通常是一维数组,要寻找任一个元素的右边或者左边第一个比自己大或者小的元素的位置,此时我们就要想到可以用单调栈了。时间复杂度为O(n)。

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
     int n = temperatures.length;
     int[] res = new int[n];
     Deque<Integer> stack = new LinkedList<>();

     for(int i=0;i<n;i++){
         while(!stack.isEmpty()&&temperatures[i]>temperatures[stack.peek()]){
             int index = stack.pop();
             res[index] = i - index;
         }
         stack.push(i);
     }
     return res;
    }
}

496.下一个更大元素 I

我自己的思路:
直接用上面的方法,求出原有的nums2 [ ] 对应的res2[ ],里面存放的是下一个大的值
然后两层for循环遍历,求出nums1[ ]对应的res1[ ]

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
        int n = nums1.length;
      int[] res1 = new int[n];
      int[] res2 = next(nums2);
      for(int i=0;i<n;i++){
          for(int j=0;j<nums2.length;j++){
              if(nums1[i] == nums2[j]){
                  res1[i] = res2[j];
              }
          }
      }
      return res1;
    }

    private int[] next(int[] nums2){
     int n = nums2.length;
     int[] res = new int[n];
     Arrays.fill(res,-1);
     Deque<Integer> stack = new LinkedList<>();

     for(int i=0;i<n;i++){
         while(!stack.isEmpty()&&nums2[i]>nums2[stack.peek()]){
             int index = stack.pop();
             res[index] =nums2[i];
         }
         stack.push(i);
     }
     return res;
    }
    
}

单调栈和哈希表

class Solution {
    public int[] nextGreaterElement(int[] nums1, int[] nums2) {
    Deque<Integer> stack = new LinkedList<>();
    HashMap<Integer,Integer> map = new HashMap<>();// 键放nums2的元素,值放比它大的最近的元素

    for(int num :nums2){
        while(!stack.isEmpty()&& num>stack.peek()){
            map.put(stack.pop(), num);
        }
        stack.push (num);
    }

    int[] res = new int[nums1.length];
    for(int i=0;i<nums1.length;i++){
       res[i] = map.getOrDefault(nums1[i],-1);
       
    }
  return res;
    }
}

503. 下一个更大元素 II

和739一模一样,只是多了扩大数组这一步

在这里插入图片描述

class Solution {
    public int[] nextGreaterElements(int[] nums) {
   Deque<Integer> stack = new LinkedList<>();
   int n = nums.length;

   int[] newArr = Arrays.copyOf(nums, 2*n); //newArr = [nums,nums] 扩展成两倍
    System.arraycopy(nums, 0, newArr, n, n);

   int[] res = new int[2*n]; //右边最近的大值
    Arrays.fill(res,-1);

   for(int i=0;i<2*n;i++){
       while(!stack.isEmpty()&&newArr[stack.peek()]<newArr[i]){
           res[stack.pop()] = newArr[i];
       }
       stack.push(i);
   }
   
   int[] newRes =  Arrays.copyOf(res, n); // 只需要前n个数据
 
  return newRes;
    }
}

不需要扩展了,想要遍历前面的数据就用:i%n来表示循环,i<2n,循环两次

class Solution {
    public int[] nextGreaterElements(int[] nums) {
   Deque<Integer> stack = new LinkedList<>();
   int n = nums.length;
   int[] res = new int[n];
   Arrays.fill(res,-1);
   
   for(int i=0;i<2*n;i++){
       int num = nums[i%n];
     while(!stack.isEmpty()&&nums[stack.peek()]< num){
       res[stack.pop()] = num;
     }
     if(i<n){
         stack.push(i);
     }
   }
   return res;
    }
}

42. 接雨水

两种方法都讲解的超级好呀!!!

方法一:
当前位置能接到的水 = MIN(前面的最大高度, 后面的最大高度)- 当前的高度

class Solution {
    public int trap(int[] height) {

        int n = height.length;
        int[] pre = new int[n]; //
        int[] next = new int[n];
        
       pre[0] = height[0];
        for(int i=1;i<n;i++){
            pre[i] = Math.max(pre[i-1],height[i]);
        }

        next[n-1] = height[n-1];
        for(int j=n-2;j>=0;j--){
            next[j]=Math.max(next[j+1],height[j]);
        }
       
       int ans =0;
       for(int i=0;i<n;i++){
          ans +=Math.min(pre[i],next[i]) - height[i];
       }
        
   return ans;
    }
}

思路二:
如果前缀最大值 < 后缀最大值, 左边 l e f t left left木桶的容量就是 前缀最大值 - h e i g h t [ i ] height[i] height[i]
如果前缀最大值 > 后缀最大值, 右边 r i g h t right right木桶的容量就是 后缀最大值 - h e i g h t [ i ] height[i] height[i]

class Solution {
    public int trap(int[] height) {
    int left =0;
    int right = height.length-1;
    int ans = 0;
    int pre = 0;
    int suf =0;

    while(left<=right){
       pre = Math.max(height[left],pre);
       suf = Math.max(height[right],suf);

       if(pre<suf){
           ans += pre - height[left];
           left++;
       }else{
           ans += suf-height[right];
           right--;
       }
    
    }
       
   return ans;
    }
}

方法三:单调栈

找左右比自己大的元素, 当前位置的面积= (矮柱子-当前高度)*两柱子之间的宽度

class Solution {
    public int trap(int[] height) {
    Deque<Integer> stack = new LinkedList<>();
    int ans =0;

    for(int i=0;i<height.length;i++){
        while(!stack.isEmpty()&& height[i] > height[stack.peek()]){
            int cur = height[stack.pop()];
            if(!stack.isEmpty()){
            int h = Math.min(height[stack.peek()],height[i]);
            ans += (h-cur)*(i-stack.peek()-1); //是两柱子之间的高度,所以-1
            }
        }
        stack.push(i);
    }
   return ans;
    }
}

84. 柱状图中最大的矩形

和上一题思路类似,找到左右两边比自己小的元素
比自己小的:所以需要单调递增的栈
每个点对应的最大面积 m a x max max =( 右边最近小 - 左边最近小 -1) * 当前高度

class Solution {
    public int largestRectangleArea(int[] heights) {
        int n = heights.length;
     int[] newH = new int[n+2];
     System.arraycopy(heights,0,newH,1,n);
     int ans =0;

     Deque<Integer> stack = new LinkedList<>();
     for(int i=0;i<n+2;i++){
         
         while(!stack.isEmpty() && newH[i]<newH[stack.peek()]){
             int cur = newH[stack.pop()];
             if(!stack.isEmpty()){
                 int l = stack.peek(); //左边比它低的
                 ans = Math.max(ans,cur*(i-l-1));
             }
         }
         stack.push(i);
     }

     return ans;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/825528.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【大数据】-- docker 启动 mysql 5.7,开启 binlog

1.说明 mysql binlog&#xff1a;二进制日志文件。它有两个作用&#xff0c;一是增量备份&#xff0c;即只备份新增的内容&#xff0c;可以用于恢复数据&#xff1b;二是用于主从复制等&#xff0c;即主节点维护了一个binlog日志文件&#xff0c;从节点从binlog中同步数据。 …

SAP-MM-采购收货操作错误的更正

业务场景: 工厂3000从供应商5555采购物料,下达采购订单时, 采购员错误操作收货101,实际为103, 收货后没有做105过账,后财务反馈未过账,采购员用MIGO+124将103冲销掉, 又重新用101收货,

助力工业物联网,工业大数据之客户回访事实指标需求分析【二十三】

文章目录 1&#xff1a;客户回访事实指标需求分析2&#xff1a;客户回访事实指标 1&#xff1a;客户回访事实指标需求分析 目标&#xff1a;掌握DWB层客户回访事实指标表的需求分析 路径 step1&#xff1a;目标需求step2&#xff1a;数据来源 实施 目标需求&#xff1a;基于客…

Redis实战(4)——Redisson分布式锁

1 基于互斥命令实现分布式锁的弊端 根据上篇文章基于redis互斥命令实现的分布式锁任然存在一定的弊端 1无法重入: 同一个线程无法重新获得同一把锁2超时删除 &#xff1a;会因为超时、任务阻塞而自动释放锁&#xff0c;出现其他线程抢占锁出现并行导致线程不安全的问题3 不可…

HTML基础介绍1

HTML是什么 1.HTML&#xff08;HyperText Mark-up Language&#xff09;即超文本标签语言&#xff08;可以展示的内容类型很多&#xff09; 2.HTML文本是由HTML标签组成的文本&#xff0c;可以包括文字、图形、动画、声音、表格、连接等 3.HTML的结构包括头部&#xff08;He…

AI绘画:当艺术遇见智能

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 前言 随着人工智能技术…

API接口给开发程序提供帮助,API接口应用价值

API可以用于开发使用相同数据的其他应用程序&#xff0c;比如公司&#xff0c;他们可以创建一个API &#xff0c;允许其他开发人员使用他们的数据并用其做其他事情&#xff0c;可以是 业务相关的 网站也可以是移动应用程序。 公司作为 信息的所有者&#xff0c; 便可以免费或收…

一次有趣的Webshell分析经历

一次有趣的Webshell分析经历 1.拉取源代码2.解密后门代码3.分析webshell逻辑4.分析404的原因5.附&#xff1a;格式化后的php代码 1.拉取源代码 在对某目标做敏感目录收集时发现对方网站备份源代码在根目录下的 backup.tar.gz&#xff0c;遂下载&#xff0c;先使用D盾分析有没有…

JS逆向-小红薯X-S环境分析

目录 前言一、分析二、验证借鉴 前言 听说这是个抓的比较严格的网址&#xff0c;这里就不作太深的分析&#xff0c;仅是将一些环境点给分析出来。 详细的可以看这位大佬的&#xff08;玩的就是一个风险转移&#xff09; 小红书x-s新版分析(2023-05-30失效) 一、分析 看波封面…

Python高阶技巧 网络编程

Socket ocket (简称 套接字) 是进程之间通信一个工具&#xff0c;好比现实生活中的插座&#xff0c;所有的家用电器要想工作都是基于插座进行&#xff0c;进程之间想要进行网络通信需要socket。 Socket负责进程之间的网络数据传输&#xff0c;好比数据的搬运工。 客户端和服务…

Element快速入门

文章目录 Element简介快速入门常见组件表格组件Pagination分页Dialog对话框Form表单 案例基本页面布局页面组件实现axios异步加载数据 vue路由打包部署 本人主攻后端&#xff0c;前端的文章基本就用来记一下的 写的文章基本没什么内容&#xff0c;还望看的多包含 Element 简介…

如何在保健品行业运用IPD?

保健品是指能调节机体功能&#xff0c;不以治疗为目的&#xff0c;并且对人体不产生任何急性、亚急性或者慢性危害的产品。保健品是食品的一个种类&#xff0c;具有一般食品的共性&#xff0c;其含有一定量的功效成分&#xff0c;能调节人体的机能&#xff0c;具有特定的功效&a…

使用Goland导出UML类图

1.安装依赖&#xff1a;goplantuml go get github.com/jfeliu007/goplantuml/parser go install github.com/jfeliu007/goplantuml/cmd/goplantumllatest 验证是否安装成功&#xff1a; 在$GOPATH的bin目录下生成.exe可执行文件&#xff1a; 2.在Goland的External Tools中添…

Java课题笔记~ MyBatis的工作流程和核心对象

一、工作流程 MyBatis的工作流程是MyBatis中重要的知识点&#xff0c;整个MyBatis工作流程分为5个步骤。 编写配置文件与映射文件&#xff1a;配置文件设置数据库连接&#xff1b;映射文件设置与SQL文件相关的操作。 MyBatis通过配置文件和映射文件生成SqlSessionFactory对象…

【第四版】 信息系统项目管理高级(高项)--第五章 信息系统工程 知识点逻辑思维导图

第五章 信息系统工程 Part1 软件工程 一、架构设计 1.软件架构目的&#xff1a;解决好软件的复用、质量、维护问题2.软件架构风格 数据流风格&#xff1a;批处理序列、管道/过滤器调用/返回风格&#xff1a;主程序/子程序独立构建风格&#xff1a;通信工程、事件驱动虚拟机风格…

年龄大了转嵌入式有机会吗?

首先&#xff0c;说下结论&#xff1a;年龄并不是限制转行嵌入式软件开发的因素&#xff0c;只要具备一定的编程和电子基础知识&#xff0c;认真学习和实践&#xff0c;是可以成为优秀的嵌入式软件开发工程师的。 1、转行建议 在转行的初期阶段&#xff0c;需要耐心学习嵌入式…

测试|LoadRunner安装及介绍

测试|LoadRunner安装及介绍 文章目录 测试|LoadRunner安装及介绍1.什么是LoadRunner2.LoadRunner特点3.LoadRunner基本概念4.LoadRunner三大组件之间关系LoadRunner安装1.安装包2.安装loadrunner 1.什么是LoadRunner LoadRunner是用来模拟用户负载完成性能测试的工具。 它适用…

Ubuntu安装Anaconda并配置Python虚拟环境

目录 1、Anaconda 1.1、下载Anaconda安装包 1.2、安装Anaconda 2、Python虚拟环境 1、Anaconda 1.1、下载Anaconda安装包 这是清华的下载镜像列表&#xff1a; Index of /https://repo.anaconda.com/archive/我们下载的是Anaconda3-2023.07-1-Linux-x86_64.sh版本。 ht…

【深度学习】Transformer,Self-Attention,Multi-Head Attention

必读文章&#xff1a; https://blog.csdn.net/qq_37541097/article/details/117691873 论文名&#xff1a;Attention Is All You Need 文章目录 1、Self-Attention 自注意力机制2、Multi-Head Attention 1、Self-Attention 自注意力机制 Query&#xff08;Q&#xff09;表示当…

【秋招】算法岗的八股文之机器学习

目录 机器学习特征工程常见的计算模型总览线性回归模型与逻辑回归模型线性回归模型逻辑回归模型区别 朴素贝叶斯分类器模型 (Naive Bayes)决策树模型随机森林模型支持向量机模型 (Support Vector Machine)K近邻模型神经网络模型卷积神经网络&#xff08;CNN&#xff09;循环神经…