算法题 子数组的最小值之和

907. 子数组的最小值之和

问题描述

给定一个整数数组arr,计算所有非空连续子数组的最小值之和。由于答案可能很大,返回结果对10^9 + 7取模。

示例

输入: 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。

算法思路

单调栈

  1. 对于每个元素arr[i],计算它作为最小值能"贡献"到多少个子数组中
  2. 找到左边第一个小于arr[i]的位置left和右边第一个小于等于arr[i]的位置right
  3. arr[i]为最小值的子数组数量为(i - left) * (right - i)
  4. 总贡献为arr[i] * (i - left) * (right - i)

为什么右边用"小于等于"而左边用"小于"?

  • 避免重复计算:当有相同元素时,统一规定只有最左边的那个元素负责计算包含这些相同元素的子数组
  • 确保每个子数组的最小值只被计算一次

代码实现

方法一:单调栈

classSolution{privatestaticfinalintMOD=1000000007;/** * 计算所有子数组最小值之和 * 使用单调栈计算每个元素的贡献度 * * @param arr 输入数组 * @return 所有子数组最小值之和(对10^9+7取模) */publicintsumSubarrayMins(int[]arr){intn=arr.length;// left[i] 表示 arr[i] 左边第一个小于 arr[i] 的元素位置,不存在则为 -1int[]left=newint[n];// right[i] 表示 arr[i] 右边第一个小于等于 arr[i] 的元素位置,不存在则为 nint[]right=newint[n];// 计算 left 数组 - 使用单调递增栈Deque<Integer>stack=newArrayDeque<>();for(inti=0;i<n;i++){// 维护单调递增栈,弹出大于等于当前元素的索引while(!stack.isEmpty()&&arr[stack.peek()]>=arr[i]){stack.pop();}// 如果栈为空,说明左边没有更小的元素left[i]=stack.isEmpty()?-1:stack.peek();stack.push(i);}// 清空栈,准备计算 right 数组stack.clear();// 计算 right 数组 - 使用单调递增栈for(inti=n-1;i>=0;i--){// 维护单调递增栈,弹出大于当前元素的索引while(!stack.isEmpty()&&arr[stack.peek()]>arr[i]){stack.pop();}// 如果栈为空,说明右边没有更小或相等的元素right[i]=stack.isEmpty()?n:stack.peek();stack.push(i);}longresult=0;// 计算每个元素的贡献度for(inti=0;i<n;i++){// 以 arr[i] 为最小值的子数组数量longcount=(long)(i-left[i])*(right[i]-i);// 累加贡献度result=(result+arr[i]*count)%MOD;}return(int)result;}}

方法二:一次遍历

classSolution{privatestaticfinalintMOD=1000000007;/** * 在单调栈弹出元素时直接计算贡献度 * * @param arr 输入数组 * @return 所有子数组最小值之和(对10^9+7取模) */publicintsumSubarrayMins(int[]arr){intn=arr.length;Deque<Integer>stack=newArrayDeque<>();longresult=0;// 添加哨兵元素简化边界处理for(inti=0;i<=n;i++){// 当 i == n 时,当前值设为 -1(确保弹出所有剩余元素)intcurrent=(i==n)?-1:arr[i];// 当栈不为空且当前元素小于栈顶元素时while(!stack.isEmpty()&&current<arr[stack.peek()]){// 弹出栈顶元素intmid=stack.pop();// 左边界:栈顶元素(如果栈为空则为 -1)intleft=stack.isEmpty()?-1:stack.peek();// 右边界:当前索引 iintright=i;// 计算以 arr[mid] 为最小值的子数组数量longcount=(long)(mid-left)*(right-mid);result=(result+(long)arr[mid]*count)%MOD;}stack.push(i);}return(int)result;}}

算法分析

  • 时间复杂度:O(n)
    • 每个元素最多入栈和出栈一次,总体线性时间
  • 空间复杂度:O(n)
    • 需要栈空间和辅助数组(方法一)或仅栈空间(方法二)

算法过程

输入:arr = [3,1,2,4]

方法一

  1. 计算 left 数组

    • i=0: 栈空 →left[0] = -1, 栈: [0]
    • i=1:arr[0]=3 >= arr[1]=1→ 弹出0,栈空 →left[1] = -1, 栈: [1]
    • i=2:arr[1]=1 < arr[2]=2left[2] = 1, 栈: [1,2]
    • i=3:arr[2]=2 < arr[3]=4left[3] = 2, 栈: [1,2,3]
    • left = [-1, -1, 1, 2]
  2. 计算 right 数组

    • i=3: 栈空 →right[3] = 4, 栈: [3]
    • i=2:arr[3]=4 > arr[2]=2→ 弹出3,栈空 →right[2] = 4, 栈: [2]
    • i=1:arr[2]=2 > arr[1]=1→ 弹出2,栈空 →right[1] = 4, 栈: [1]
    • i=0:arr[1]=1 < arr[0]=3right[0] = 1, 栈: [1,0]
    • right = [1, 4, 4, 4]
  3. 计算贡献度

    • i=0:count = (0-(-1)) * (1-0) = 1*1 = 1, 贡献 =3*1 = 3
    • i=1:count = (1-(-1)) * (4-1) = 2*3 = 6, 贡献 =1*6 = 6
    • i=2:count = (2-1) * (4-2) = 1*2 = 2, 贡献 =2*2 = 4
    • i=3:count = (3-2) * (4-3) = 1*1 = 1, 贡献 =4*1 = 4
    • 总和 =3+6+4+4 = 17

测试用例

publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:标准示例int[]arr1={3,1,2,4};System.out.println("Test 1: "+solution.sumSubarrayMins(arr1));// 17// 测试用例2:递增数组int[]arr2={1,2,3,4};System.out.println("Test 2: "+solution.sumSubarrayMins(arr2));// 20// [1]+[2]+[3]+[4]+[1,2]+[2,3]+[3,4]+[1,2,3]+[2,3,4]+[1,2,3,4]// = 1+2+3+4+1+2+3+1+2+1 = 20// 测试用例3:递减数组int[]arr3={4,3,2,1};System.out.println("Test 3: "+solution.sumSubarrayMins(arr3));// 20// 每个子数组的最小值都是最后一个元素// 测试用例4:相同元素int[]arr4={2,2,2};System.out.println("Test 4: "+solution.sumSubarrayMins(arr4));// 12// [2]+[2]+[2]+[2,2]+[2,2]+[2,2,2] = 2+2+2+2+2+2 = 12// 测试用例5:单元素int[]arr5={5};System.out.println("Test 5: "+solution.sumSubarrayMins(arr5));// 5// 测试用例6:大数值(测试取模)int[]arr6={100000};System.out.println("Test 6: "+solution.sumSubarrayMins(arr6));// 100000// 测试用例7:复杂情况int[]arr7={71,55,82,55};System.out.println("Test 7: "+solution.sumSubarrayMins(arr7));// 539// 测试用例8:包含0int[]arr8={3,0,2,1};System.out.println("Test 8: "+solution.sumSubarrayMins(arr8));// 7}

关键点

  1. 贡献度

    • 不直接枚举所有子数组,而是计算每个元素作为最小值的贡献
  2. 单调栈

    • 用于高效找到每个元素左右边界
    • 左边找"小于",右边找"小于等于"避免重复计算
  3. 边界处理

    • 不存在更小元素时,左边界为-1,右边界为n
    • 计算的子数组数量公式统一为(i-left) * (right-i)
  4. 数据类型

    • 使用long防止中间计算溢出
    • 最后对10^9 + 7取模
  5. 哨兵

    • 方法二中在数组末尾添加哨兵元素,简化边界处理
    • 确保所有元素最终都会被弹出并计算贡献

常见问题

  1. 为什么右边用"小于等于"而左边用"小于"?

    • 处理重复元素的情况,确保每个子数组只被计算一次
    • 如果两边都用"小于",重复元素会被重复计算
    • 如果两边都用"小于等于",可能会漏掉某些情况
  2. (i-left) * (right-i)公式?

    • (i-left)表示以arr[i]为右端点的左边界选择数量
    • (right-i)表示以arr[i]为左端点的右边界选择数量
    • 两者相乘就是所有包含arr[i]arr[i]为最小值的子数组数量

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

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

相关文章

网络安全知识图谱硬核梳理:从基础到原理,从入门到实战的完整体系

随着互联网的普及和数字化进程的加速&#xff0c;网络安全已经成为我们生活中不可或缺的一部分。然而&#xff0c;很多人对于网络安全的概念仍然模糊不清。 那么&#xff0c;什么是网络安全&#xff1f;它究竟有多重要呢&#xff1f; 一、网络安全的定义 网络安全是指通过采取…

疑问解答:M2FP是否支持视频流实时解析?答案是肯定

疑问解答&#xff1a;M2FP是否支持视频流实时解析&#xff1f;答案是肯定 &#x1f9e9; M2FP 多人人体解析服务 (WebUI API) 项目背景与核心价值 在计算机视觉领域&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 是一项比通用语义分割更精细的任务&#xff0…

M2FP更新日志:新增自动颜色映射,提升可视化体验

M2FP更新日志&#xff1a;新增自动颜色映射&#xff0c;提升可视化体验 &#x1f4d6; 项目简介&#xff1a;M2FP 多人人体解析服务 在计算机视觉领域&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 是一项关键的细粒度语义分割任务&#xff0c;旨在将人体分解为多…

Python---面向对象的基本概念

一、面向对象的核心思想面向对象编程的核心是以 “对象” 为中心组织代码&#xff0c;把现实世界中的事物抽象为程序中的 “对象”&#xff0c;每个对象包含&#xff1a;属性&#xff1a;描述事物的特征&#xff08;如人的姓名、年龄&#xff0c;手机的品牌、价格&#xff09;&…

空间选择性ALE的两种工艺路径

空间选择性ALE的两种工艺路径 之前&#xff0c;我们聊过什么是ALE&#xff0c;详见文章&#xff1a;什么是原子层刻蚀&#xff08;ALE&#xff09;&#xff1f; 什么是空间选择性ALE&#xff1f; 空间选择性 ALE&#xff08;Spatially selective ALE&#xff09;&#xff0c…

空间选择性ALE的两种工艺路径

空间选择性ALE的两种工艺路径 之前&#xff0c;我们聊过什么是ALE&#xff0c;详见文章&#xff1a;什么是原子层刻蚀&#xff08;ALE&#xff09;&#xff1f; 什么是空间选择性ALE&#xff1f; 空间选择性 ALE&#xff08;Spatially selective ALE&#xff09;&#xff0c…

Z-Image-Turbo皮影戏风格图像生成实验

Z-Image-Turbo皮影戏风格图像生成实验 引言&#xff1a;当AI遇见传统艺术——皮影戏风格的探索之旅 在AI图像生成技术飞速发展的今天&#xff0c;我们不再满足于简单的“高清照片”或“动漫风格”&#xff0c;而是开始尝试将传统文化元素与现代生成模型深度融合。阿里通义推出的…

真实案例:某服装品牌用M2FP构建虚拟换装系统降本60%

真实案例&#xff1a;某服装品牌用M2FP构建虚拟换装系统降本60% 在数字化营销与个性化体验日益重要的今天&#xff0c;虚拟试衣已成为服装零售行业提升转化率、降低退货成本的关键技术。然而&#xff0c;传统方案依赖高精度3D建模和GPU集群推理&#xff0c;部署成本高昂&#x…

金电镀凸块的应用

金电镀凸块的应用什么是金凸块&#xff1f;金凸块&#xff08;Gold Bump / Au Bump&#xff09;是做在芯片焊盘&#xff08;Pad&#xff09;上的一类微型“凸起金属端子”&#xff0c;材料以金&#xff08;Au&#xff09;为主&#xff0c;用来把芯片与外部基板/玻璃/柔性板实现…

金电镀凸块的应用

金电镀凸块的应用什么是金凸块&#xff1f;金凸块&#xff08;Gold Bump / Au Bump&#xff09;是做在芯片焊盘&#xff08;Pad&#xff09;上的一类微型“凸起金属端子”&#xff0c;材料以金&#xff08;Au&#xff09;为主&#xff0c;用来把芯片与外部基板/玻璃/柔性板实现…

模型融合技巧:结合M2FP与其他CV模型

模型融合技巧&#xff1a;结合M2FP与其他CV模型 &#x1f4d6; 项目背景与技术痛点 在计算机视觉领域&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 是一项基础但极具挑战的任务。它要求对图像中的人体进行像素级语义分割&#xff0c;精确识别出如头发、面部、上…

Z-Image-Turbo故障艺术(Glitch Art)特效实现

Z-Image-Turbo故障艺术&#xff08;Glitch Art&#xff09;特效实现 引言&#xff1a;从AI图像生成到数字美学实验 在当代数字艺术创作中&#xff0c;故障艺术&#xff08;Glitch Art&#xff09; 作为一种反常规、反完美的视觉表达形式&#xff0c;正逐渐被艺术家和开发者所…

M2FP色彩映射表:各身体部位对应颜色编码说明

M2FP色彩映射表&#xff1a;各身体部位对应颜色编码说明 &#x1f9e9; M2FP 多人人体解析服务 在计算机视觉领域&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 是一项关键的细粒度语义分割任务&#xff0c;旨在将人体图像划分为多个具有明确语义的身体部位区域。…

无需CUDA也能做人像分割?M2FP CPU镜像填补无卡用户空白

无需CUDA也能做人像分割&#xff1f;M2FP CPU镜像填补无卡用户空白 &#x1f4d6; 项目简介&#xff1a;M2FP 多人人体解析服务 在当前AI视觉应用日益普及的背景下&#xff0c;人像语义分割已成为图像编辑、虚拟试衣、智能安防等场景的核心技术之一。然而&#xff0c;大多数高性…

性能提升300%:M2FP模型推理优化全记录

性能提升300%&#xff1a;M2FP模型推理优化全记录 &#x1f4cc; 背景与挑战&#xff1a;多人人体解析的工程落地难题 在智能视觉应用中&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 是一项关键基础能力&#xff0c;广泛应用于虚拟试衣、动作识别、人像美化和安…

晶圆电镀的阳极钝化是什么?

晶圆电镀的阳极钝化是什么&#xff1f; 这个是可溶性阳极的常见问题&#xff0c;关于什么是可溶性阳极&#xff0c;可以参考之前文章&#xff1a;电镀机的阳极是什么材质&#xff1f; 用一句通俗的话来概括阳极钝化就是原本应该顺畅溶解、补充金属离子的阳极&#xff0c;因为…

晶圆电镀的阳极钝化是什么?

晶圆电镀的阳极钝化是什么&#xff1f; 这个是可溶性阳极的常见问题&#xff0c;关于什么是可溶性阳极&#xff0c;可以参考之前文章&#xff1a;电镀机的阳极是什么材质&#xff1f; 用一句通俗的话来概括阳极钝化就是原本应该顺畅溶解、补充金属离子的阳极&#xff0c;因为…

人体解析模型选型困惑?M2FP在准确性和易用性上实现双赢

人体解析模型选型困惑&#xff1f;M2FP在准确性和易用性上实现双赢 在当前计算机视觉应用日益深入的背景下&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 已成为智能服装推荐、虚拟试衣、人像编辑、AR互动等场景的核心技术之一。然而&#xff0c;在实际项目落地…

你还在手动拼接mask?M2FP内置算法自动生成彩色分割图

你还在手动拼接mask&#xff1f;M2FP内置算法自动生成彩色分割图 &#x1f4d6; 项目简介&#xff1a;M2FP 多人人体解析服务 在计算机视觉领域&#xff0c;人体解析&#xff08;Human Parsing&#xff09; 是一项细粒度的语义分割任务&#xff0c;目标是将人体图像中的每个像素…

基于SpringBoot的图书馆在线占座系统设计与实现

一、系统开发背景与意义 随着高校扩招与阅读需求增长&#xff0c;图书馆座位资源紧张问题日益突出。传统线下占座模式存在诸多弊端&#xff1a;早到占位却长时间空置导致资源浪费&#xff0c;人工登记繁琐易引发纠纷&#xff0c;学生难以实时掌握座位使用情况&#xff0c;常因“…