leetcode907. 子数组的最小值之和(单调栈-java)

news2024/9/17 9:10:08

子数组的最小值之和

  • leetcode907. 子数组的最小值之和
    • 题目描述
    • 单调栈解法一
    • 代码演示
    • 单调栈解法二
  • 单调栈专题

leetcode907. 子数组的最小值之和

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sum-of-subarray-minimums

题目描述

给定一个整数数组 arr,找到 min(b) 的总和,其中 b 的范围为 arr 的每个(连续)子数组。
由于答案可能很大,因此 返回答案模 10^9 + 7 。

示例 1:
输入:arr = [3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。

示例 2:
输入:arr = [11,81,94,43,3]
输出:444

提示:
1 <= arr.length <= 3 * 104
1 <= arr[i] <= 3 * 104

单调栈解法一

由于我们是从子数组中取最小值来进行累加,即参与答案构成的每个数必然某个具体的。
因此我们可以将原问题转化为「考虑统计每个对答案的贡献」。

对于某一个
而言,我们考虑其能够作为哪些子数组的最小值。
我们可以想象以
为中心,分别往两端进行拓展,只要新拓展的边界不会改变「
为当前子数组的最小值」的性质即可。
换句话说,我们需要找到
作为最小值的最远左右边界,即找到
左右最近一个比其小的位置 l 和 r。
在给定序列中,找到任意
近一个比其大/小的位置,可使用「单调栈」进行求解。
到这里,我们会自然想到,通过单调栈的方式,分别预处理除 l 和 r 数组:
l[i] = loc 含义为下标 i 左边最近一个比 arr[i] 小的位置是 loc(若在
左侧不存在比其小的数,则 loc = -1)
r[i] = loc 含义为下标 i 右边最近一个比 arr[i] 小的位置是 loc(若在
左侧不存在比其小的数,则 loc = n)
当我们预处理两数组后,通过简单「乘法原理」即可统计以
为最小值时,子数组的个数:
包含 的子数组左端点个数为个包含的子数组右端点个数为个子数组的个数子数组最小值 ,即是当前 对答案的贡献:
统计所有
对答案的贡献即是最终答案,但我们忽略了「当 arr 存在重复元素,且该元素作为子数组最小值时,最远左右端点的边界越过重复元素时,导致重复统计子数组」的问题。
看图理解:
在这里插入图片描述
为了消除这种重复统计,我们可以将「最远左右边界」的一端,从「严格小于」调整为「小于等于」,从而实现半开半闭的效果。

代码演示

  /**
     * 子数组最小值之和
     * @param arr
     * @return
     */
    public static int sumSubarrayMins(int[] arr) {
        int[] stack = new int[arr.length];
        int[] left = nearLessEqualLeft(arr, stack);
        int[] right = nearLessEqualRight(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 * (long)arr[i];
            ans %= 1000000007;
        }
        return (int)ans;
    }

    /**
     * 记录比当前数字小的左边界
     * @param arr
     * @param stack
     * @return
     */
    public static int[] nearLessEqualLeft(int[] arr, int[] stack) {
        int N = arr.length;
        int[] left = new int[N];
        int size = 0;
        for (int i = N - 1; i >= 0;i--){
            while (size != 0 && arr[stack[size - 1]] >= arr[i]){
                left[stack[--size]] = i;
            }
            stack[size++] = i;
        }
        while (size != 0){
            left[stack[--size]] = -1;
        }
        return left;
    }

    /**
     * 记录比当前数字小的右边界
     * @param arr
     * @param stack
     * @return
     */
    public static int[] nearLessEqualRight(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[stack[size - 1]] > arr[i]){
                right[stack[--size]] = i;
            }
            stack[size++] = i;
        }
        while (size != 0){
            right[stack[--size]] = N;
        }
        return right;
    }

单调栈解法二

可以对获取左右边界位置的方法,放在一起,进行优化下.

class Solution {

     int MOD = (int)1e9+7;
    public int sumSubarrayMins1(int[] arr) {
        int n = arr.length, ans = 0;
        int[]d = new int[arr.length];
        int size = -1;
        for (int r = 0; r <= n; r++) {
            int t = r < n ? arr[r] : 0;
            while (size != -1 && arr[d[size]] >= t) {
                int cur = d[size--];
                int l = size == -1 ? -1 : d[size];
                int a = cur - l, b = r - cur;
                ans += a * 1L * b % MOD * arr[cur] % MOD;
                ans %= MOD;
            }
            d[++size] = r;
        }
        return ans;
    }
}

单调栈专题

单调栈的实现-单调递减栈和单调递增栈

leetcode1856. 子数组最小乘积的最大值

leetcode84. 柱状图中最大的矩形

leetcode.85. 最大矩形

leetcode42. 接雨水

leetcode739. 每日温度

leetcode.1504. 统计全 1 子矩形

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

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

相关文章

如何快速学习一门计算机语言

如何快速学习一门计算机语言 掌握一门语言的基本数据类型和基本语法。掌握语言里数组和集合工具类的使用掌握循环分支控制掌握一下该计算机语言面向对象或者函数式编程的特征对异常或者错误的处理文件读写&#xff0c;输入输出流字符串的处理日志的打印运行时module或者librar…

【C语言基础】函数

C语言中的函数是模块化编程的基础&#xff0c;通过函数的定义、实参与形参的传递以及函数的调用流程&#xff0c;我们可以实现代码的重用和逻辑的封装。本文将深入探讨C语言函数的定义方式、实参与形参的传递机制&#xff0c;以及函数的调用流程和局部变量与栈内存的关系。 一、…

企业快递管理制定教程

在经济飞速发展的助力之下&#xff0c;现代企业接触到的制度越来越多&#xff0c;除了我们熟知的CRM、OA等等&#xff0c;管理制度进一步细分。企业寄件在企业内部运转中的地位越发重要&#xff0c;随之也产生了快递管理制度。不少人就会问&#xff1a;有必要这么细分吗&#x…

跨应用连接同一个redis,从redis取缓存,对象属性值都为null

本地idea部署和docker部署问题&#xff0c;连接同一个redis&#xff0c;idea项目的redis缓存&#xff0c;docker中取不到&#xff0c;docker中缓存的redis本地取不到 ✅ 原因&#xff1a;idea本地代码实体类未进行代码混淆&#xff0c;docker代码实体类进行了混淆&#xff0c;…

Caused by: java.io.IOException: CreateProcess error=206, 文件名或扩展名太长

java.io.IOException: Cannot run program "D:\javaAPP\jdk\bin\java.exe" (in directory "D:\java\demo"): CreateProcess error206, 文件名或扩展名太长。 Caused by: java.io.IOException: CreateProcess error206, 文件名或扩展名太长。 删除项目.ide…

Vue -- 生命周期 数据共享

1 组件的生命周期 1.1 生命周期 & 生命周期函数 生命周期&#xff08;Life Cycle&#xff09;是指一个组件从创建 -> 运行 -> 销毁的整个阶段&#xff0c;强调的是一个时间段。 生命周期函数&#xff1a;是由 vue 框架提供的内置函数&#xff0c;会伴随着组件的生命…

leetcode极速复习版-第一章数组

目录 数组 数组理论基础 704二分查找 27移除元素 977.有序数组的平方 209.长度最小的子数组 59.螺旋矩阵II 数组部分总结 数组 数组理论基础 数组的元素是不能删的&#xff0c;只能覆盖。 二维数组&#xff1a; 704二分查找 二分法 middle int(left right)的int 直接对着一个…

SSM学习笔记-------SpringMVC(一)

SSM学习笔记-------SpringMVC_day01 SpringMVC_day011、SpringMVC简介1.1 SpringMVC概述 2、SpringMVC入门案例2.1 需求分析2.2 案例制作步骤1:创建Maven项目&#xff0c;并导入对应的jar包步骤2:创建控制器类步骤3:创建配置类步骤4:创建Tomcat的Servlet容器配置类步骤5:配置To…

【2022吴恩达机器学习课程实验翻译笔记】 Python 和 Jupyter Notebook 简介

为了看着比较连贯&#xff0c;我直接翻译了&#xff0c;不放英文原文对照了 选修实验课: Python 和 Jupyter Notebook 简介 欢迎来到第一节选修实验课 选修实验课的目的是&#xff1a; 提供信息&#xff0c;就像这个notebook一样通过实例加深对课程的理解展示在课程中使用的…

【Unity实战】制作类元气骑士、挺进地牢——俯视角射击游戏多种射击效果(二)(附源码)

文章目录 前言一、火箭筒1. 编写火箭筒脚本2. 创建火箭弹和新爆炸特效的预制体3. 编写火箭弹脚本4. 设置好火箭弹和火箭筒的脚本和参数5. 运行效果 二、激光枪1. 编写激光枪脚本2. 先运行游戏&#xff0c;看看效果3. 美化射线4. 完善代码5. 再次运行游戏6. 升级URP项目7. 后处理…

剑指offer13.机器人的运动范围

一开始没看清题目&#xff0c;没看到要一步一步移动&#xff0c;我以为是看所有格子中有几个格子符合条件&#xff0c;就直接遍历所有格子&#xff0c;把每个格子的i&#xff0c;j每个位数上的数相加看看是否小于k&#xff0c;是就给counts加一最后返回couts&#xff0c;我还说…

OSPF小实验

OSPF小实验 要求&#xff1a; 1、地址配置 R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; R6&#xff1a; 2、启用R1-R3的ospf&#xff0c;划分为区域0 R1&#xff1a; R2&#xff1a; R3&#xff1a; 3、R1-R2之间采用ppp的pap单向认证 R1为…

select + option 获取 value 来 innerHTML 插入内容或元素

目录 select optioninnerHTML 在元素中插入内容 select option 可以实现一个下拉选择&#xff0c;选择到那个&#xff0c;就可以获取其value&#xff0c;并且弹窗。 <!DOCTYPE HTML> <html><head><meta charset"utf-8"><style>.st…

【数据结构与算法】查找课后习题

题目 下面一共有4道有关查找的课后习题&#xff0c;全部都是思路题、画图题并不是完整的算法设计题故在此就一起列举出来了~ 1. 已知一个有序表的表长为8N&#xff0c;并且表中没有关键字相同的记录 假设按如下所述方法查找一个关键字等于给定值K的记录&#xff1a;先在第8,1…

Jmeter性能优化方案

最近用jmeter测试并发出现了访问端口异常问题的排查及解决方案做一个归纳&#xff1a; 背景&#xff1a;接口压测异常情况发生率达到了99% 线上情况&#xff1a; 错误情况展示&#xff1a; 原因&#xff1a; Jmeter里的http sample勾选了keep alive&#xff0c;导致会话一直…

2022年真题 - 16 - cockpit

cockpit 题目配置 题目 安装 cockpit 来检测 ispsrv 服务器的状态 配置 安装 cockpit [rootStorageSrv ~]# yum -y install cockpit启动服务 [rootStorageSrv ~]# systemctl enable --now cockpit.socketInsideCli 浏览器访问 http://192.168.100.200:9090

【数据结构与算法】假设图采用邻接表存储,判断一个未知顶点个数和边数的无向连通图G是否是棵树

题目 Qestion: 设计一个算法,判断一个未知顶点个数和边数的无向连通图G是否是棵树,假设图采用邻接表存储。若是树,返回true;否则返回 false。 (用图1和图2验证作业题2算法的正确性) 图一图二的邻接表结构 运行结果以及其解释 由结果可知图一为无向连通图&#xff0c;图二不为…

基于Arcgis 一带一路地图制作 沿途主要城市 路线

数据准备&#xff1a; 全球范围的DEM地形数据 海上丝绸之路节点城市shp陆上丝绸之路节点城市shp全球行政区域shp 全球的shp和主要城市 数据&#xff1a;下载 海上丝绸之路节点城市和陆上丝绸之路节点城市shp&#xff1a;下载 一带一路沿途经济走廊shp&#xff1a;下载 数据…

【Linux】Linux基础命令-cp、ls、mv、chmod、rm、mkdir、cd、find、pwd

1.添加用户 &#xff08;1&#xff09;切换到管理员 sudo su &#xff08;2&#xff09;添加用户 addusr zhangdi &#xff08;3&#xff09;设置密码 &#xff08;4&#xff09;切换到自己的账号 su zhangdi 2.mkdir、cd命令&#xff0c;要求能建立目录、进入与退出目录 &a…

Linux下打包发布QT程序,并运行在其他没有安装QT环境的linux系统上

一、Linux下打包发布步骤如下 编译应用程序环境&#xff1a;ubuntu18.04版本开发环境&#xff1a;Qt5.14.2编译环境&#xff1a;gcc_64要移植的电脑&#xff1a;ubuntu18.04版本&#xff0c;没有开发环境 第一步&#xff1a;打包依赖库 1、创建一个打包目录&#xff0c;把生…