单调栈练习(五)— 子数组的最小值之和

题目
同样的LeetCode原题:题目链接

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。

由于答案可能很大,因此 返回答案模 10^9 + 7 。

在这里插入图片描述

思路

暴力解
先来说暴力解的思路:
三层for循环,找到每一个子数组中的最小值,0-0,0-1,0-2 … 0-N。1-1,1-2,1-3…1-N。并将每一个子数组的最小值相加即可,时间复杂度 O ( N 3 ) O(N^3) O(N3)

在这里插入图片描述

代码

public static int subArrayMinSum2(int[] arr) {if (arr == null || arr.length == 0) {return 0;}int N = arr.length;int ans = 0;for (int i = 0; i < N; i++) {for (int j = i; j < N; j++) {int min = arr[i];for (int k = i + 1; k <= j; k++) {min = Math.min(min, arr[k]);}ans += min;}}return ans;}

优化的普通解

优化的方法是根据题目中给定的 arr[],生成对应的 left[] 和 right[]。

left[]:left[i] = x ,表示左侧最近 <= arr[i] 的位置在 x(x表示对应的索引)
right[]:right[i] = y,表示右侧最近 < arr[i] 的位置在y(y表示对应的索引)

生成 left[] 和 right[]的作用在于,根据当前子数组中最小值 arr[i] 在 left[]、right[]中获取左右最小且近的边界值后,直接进行计算求出以 arr[i] 作为子数组最小值的累加和,优化后的时间复杂度是 O ( N ) O(N) O(N)

来看下面的例子:当前 arr[8] = 7 ,找到左侧最近且小的值在是4位置的3,右侧最近且小的值是12位置4。
在这里插入图片描述

此时,以7作为最小值的子数组范围是 5 ~ 11,并且此范围内所有值都是 >= 7 的,但是因为要以7作为最小值,所以5 ~ 11范围内所求的子数组要把8位置的7涵盖进去。此时利用 left[8] = 4 、right[8] = 12, (8 - 4)x(12 - 8)x (arr[8]) = 112,就是7作为最小值的时候所有子数组最小值的累加和。

需要注意的是:如果是普通的无重复值数组,那么很好处理,但如果数组中有重复值,就需要额外注意!!!

举例:
在这里插入图片描述
碰上有重复值的数组,要稍微多考虑一些,就是左右边界的设定选择改怎么选?本题中答案选用的是第一种

两种选择的不同其实目的都是一个,那就是抛去重复值的计算

比如说:
此时以4位置的3作为最小值,如果依然是从1位置开始枚举每个子数组 1 - 4 、 1 - 5 … 1 - 11,那等到以7位置的3作为最小值时呢? 此时如果再从1 - 7、 1 - 8 … 1 - 11。那么和之前计算的子数组最小值就包含了重复的部分。所以要去重。

代码

构建完成后,遍历一遍 arr[] , 将每一个值都作为子数组的最小值,并根据 left[]、right[] 算出子数组的个数,个数 * 最小值,不就是我们想要的答案,再将求出来的每一个结果进行累加。

 public static int subArrayMinSum2(int[] arr) {if (arr == null || arr.length == 0) {return 0;}int[] left = leftNearLessEqual1(arr);int[] right = rightNearLess1(arr);int ans = 0;for (int i = 0; i < arr.length; i++) {int start = i - left[i];int end = right[i] - i;ans += start * end  * arr[i];}return ans;}public static int[] rightNearLess1(int[] arr) {int N = arr.length;int[] right = new int[N];int ans;for (int i = 0; i < N; i++) {ans = N;for (int j = i + 1; j < N; j++) {if (arr[j] < arr[i]) {ans = j;break;}}right[i] = ans;}return right;}public static int[] leftNearLessEqual1(int[] arr) {int N = arr.length;int[] left = new int[N];int ans;for (int i = N - 1; i >= 0; i--) {ans = -1;for (int j = i - 1; j >= 0; j--) {if (arr[j] <= arr[i]) {ans = j;break;}}left[i] = ans;}return left;}

单调栈
单调栈其实就是将构建left[]、right[]的过程加快了,其逻辑是不变的。
这里的单调栈是自己用数组实现,没有用系统提供的Stack,但是照比系统提供的性能要更好一些。

 public static int sumSubarrayMins(int[] arr) {if (arr == null || arr.length == 0) {return 0;}int[] stack = new int[arr.length];int[] left = leftNearLessEqual2(arr, stack);int[] right = rightNearLess2(arr, stack);long ans = 0;for (int i = 0; i < arr.length; i++) {long start = i - left[i];long end = right[i] - i;ans += (start * end) * arr[i];ans %= 1000000007;}return (int)ans;}public static int[] rightNearLess2(int[] arr,int[] stack) {int N = arr.length;int[] right = new int[N];int size = 0;for (int i = 0; i < N; i++) {while (size != 0 && arr[i] < arr[stack[size - 1]]){right[stack[--size]] = i;}stack[size++] = i;}while (size != 0){right[stack[--size]] = N;}return right;}public static int[] leftNearLessEqual2(int[] arr,int[] stack) {int N = arr.length;int[] left = new int[N];int size = 0;for (int i = N - 1; i >= 0; i--) {//stack[size - 1] :当前最后加入到数组中元素即为栈顶元素//stack[--size] :出栈操作,弹出栈顶元素并且大小 - 1,后加入的元素要覆盖当前位置while (size != 0 && arr[i] <= arr[stack[size - 1]]){//当前 i 位置 使栈顶元素出栈,所以 left[栈顶元素左侧小且近] = 当前下标 ileft[stack[--size]] = i;}//入栈操作:存储当前元素索引stack[size++] = i;}while (size != 0){left[stack[--size]] = -1;}return left;}

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

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

相关文章

OpenssH 漏洞修复

文章目录 OpenSSH 漏洞修复需求&#xff1a;准备环境配置阿里云yum源关闭防火墙 && SELinux安装 telnet-server安装 zlib 软件包安装OpenssL安装 OpenssH报错信息 OpenSSH 漏洞修复 场景&#xff1a; CentOS Stream 9 系统ssh默认版本一般是OpenSSH_8.7p1 &#xff0c;…

【国内访问github不稳定】可以尝试fastgithub解决这个问题

1、下载 https://github.com/dotnetcore/FastGithub https://github.com/dotnetcore/FastGithub/releases 官网下载即可&#xff0c;比如&#xff0c;我用的是这个&#xff1a;fastgithub_osx-x64.zip&#xff08;点这里下载&#xff09; 2、安装 如下图双击启动即可 3、…

科研绘图(二)气泡图

气泡矩阵图&#xff08;Bubble Matrix Plot&#xff09;&#xff0c;通常用于显示三个变量之间的关系。这种图表类型将数据点表示为气泡的形式&#xff0c;其中气泡的大小通常表示第三个数值变量的大小。图表的X轴和Y轴代表两个分类或定量变量。颜色可能代表另一个分类变量或是…

CAN总线通信详解 (超详细配34张高清图)

CAN总线通信详解 (超详细配34张高清图) 1. CAN总线历史 CAN 是 Controller Area Network 的缩写&#xff08;以下称为 CAN&#xff09;&#xff0c;是 ISO国际标准化的串行通信协议。 在当前的汽车产业中&#xff0c;出于对安全性、舒适性、方便性、低公害、低成本的要求&#…

Python爬虫---scrapy shell 调试

Scrapy shell是Scrapy提供的一个交互式shell工具&#xff0c;它可以帮助我们进行爬虫的开发和调试。可以使用它来测试xpath或css表达式&#xff0c;查看它们是如何工作的&#xff0c;以及它们从你试图抓取的网页中提取的数据。它允许你在编写spider时交互地测试表达式&#xff…

ipad协议滑块讲解-3(2000038登录滑块)

请使用python进行编译失调&#xff0c;切勿用于非法用途&#xff01;&#xff01; 创建main.js脚本 代码如下 const {VM,VMScript} require("vm2"); const fs require("fs"); const {read} require("./env/main"); const {readJsCode} re…

图像异或加密及唯密文攻击

异或加密 第一种加密方式为异或加密&#xff0c;异或加密的原理是利用异或的可逆性质&#xff0c;原始图像的像素八位bit分别与伪随机二进制序列异或&#xff0c;得到的图像就为加密图像。如下图对lena图像进行加密。 伪随机序列为一系列二进制代码&#xff0c;它受加密秘钥控…

【重点!!!】【DP】354. 俄罗斯套娃信封问题

题目 法1&#xff1a;DP&#xff0c;LIS问题 基本方法&#xff0c;必须掌握&#xff01;&#xff01;&#xff01; class Solution {public int maxEnvelopes(int[][] envelopes) {int n envelopes.length;if (n < 2) {return n;}Arrays.sort(envelopes, (a1, a2) ->…

php文件实战分析

1.php文件分析如下 这段代码是一个简单的 PHP 文件上传处理脚本。让我来为你进行分析&#xff1a; 首先&#xff0c;通过检查 $_FILES["file"]["error"] 的值来确定是否发生了错误。如果 $_FILES["file"]["error"] 大于 0&#xff0c…

CSS样式学习

html超文本传输标签&#xff0c;属性等权重 outline 标签轮廓 <input type"text"> <textarea cols"30" rows"10"></textarea> outline: none; 表示无轮廓 &#xff08;开发时用的比较多&#xff09; CSS 轮廓&#xff…

数据结构入门到入土——栈(Stack)和队列(Queue)

目录 一&#xff0c;栈&#xff08;Stack&#xff09; 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1.5 栈&#xff0c;虚拟机栈&#xff0c;栈帧有什么区别&#xff1f; 二&#xff0c;队列&#xff08;Queue&#xff09; 2.1 概念 2.2 队列的使用 2.3 …

H3C在交换机上查找一个IP

一、案例背景&#xff1a; 一台wifi&#xff0c;在防火墙上有此IP的安全告警&#xff0c;需要查找到这个端口&#xff0c;并改到其他的隔离网段上网 二、排查过程&#xff1a; 自上向下查&#xff1a;在汇聚交换机上ping了一下&#xff0c;通的&#xff0c;然后查了下mac&…

前端js调用Lodop实现云打印

一、下载Lodop控件 官网&#xff1a;下载中心 - Lodop和C-Lodop官网主站 二、解压后安装 双击进行安装&#xff0c;里面有些页面文件是一些教程案例 勾选云服务工作模式 安装成功会自动启动 浏览器访问地址&#xff1a;http://localhost:8000/ 首页最下面有个教程案例跳转地址&…

DNS 域名解析

一 、名字解析介绍和DNS 当前TCP/IP网络中的设备之间进行通信&#xff0c;是利用和依赖于IP地址实现的。但数字形式的IP地址是很难记忆的。当网络设备众多&#xff0c;想要记住每个设备的IP地址&#xff0c;可以说是"不可能完成的任务"。那么如何解决这一难题呢&…

独孤思维:​凌驾于所有赚钱项目的副业

01 混群&#xff0c;尤其是混付费群。 在群里不要爆fen&#xff0c;不要广告。 真诚分享你的副业心得&#xff0c;经验&#xff0c; 自然能吸引到别人&#xff0c;主动加你。 这样&#xff0c;你就多了一个精准获客的方法。 02 不要在乎眼前的成绩。 没有意义。 独孤写…

蓝桥杯单片机进阶教程4——需要分配进程的模块

前言&#xff1a; 【蓝桥杯单片机保姆级教学】 https://www.bilibili.com/video/BV1h3411m7Aw/?p117&share_sourcecopy_web&vd_sourcec4fc67867c5218768e783d04475bc5a2 P117-118 比赛的时候也按照这个顺序来写 一、数码管显示 分析考题 &#xff08;1&#xff09;…

Go语言的内存分配器

1. 内存分配器的历史 Go语言的第一个内存分配器是简单的伙伴分配器。伙伴分配器是一种经典的内存分配器&#xff0c;它将堆内存划分为多个大小相同的块&#xff0c;并使用一种递归的算法来分配和释放内存块。伙伴分配器简单高效&#xff0c;但它存在一个问题&#xff1a;当分配…

javascript_forEach中使用异步函数执行顺序问题,错误原因+解决思路

javascript_forEach中使用异步函数执行顺序问题&#xff0c;错误原因解决思路 start 最近在写异步逻辑的时候&#xff0c;经常会使用 async/await。有些时候需要执行异步逻辑的函数比较多&#xff0c;就习惯用 forEachasync/await 去处理函数了。在测试的过程中会发现&#x…

Unity之角色控制器

PS:公司终于给我派任务了&#xff0c;最近几天都没学Unity&#x1f927;。 一、角色控制器的实现方式 目前小编知道的角色控制器实现方式有三种&#xff1a; 应用商店的角色控制系统Unity自己的角色控制器通过物理系统去做角色控制器 本篇介绍的是第二种Unity自己的角色控制…

数字化时代,VR全景展示如何让用户一窥全貌?

数字化时代&#xff0c;VR全景展示为各行各业提供了无限的可能性。随着VR全景技术的逐步普及&#xff0c;VR全景展示以其独特的呈现方式和新颖十足的交互体验&#xff0c;正在不断改变着人们对于展示宣传的理解。 传统的展示方式&#xff0c;通常需要将产品、图文、品牌等元素集…