题目:

给定一个整数数组 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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/sum-of-subarray-minimums
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

先记录一下我没通过的解题思路:

我想利用双循环来解题,外层循环表示从连续子数组的开始,内层循环表示连续子数组的结束,这样数组中的每个单个元素也能相加,遍历过程中也能更新最小值,以及得到求和,最后将和与10^9 + 7取模即可。

但是用例过不去,我还找不出来原因,哭了我这个小垃圾~

问题代码:

 1 class Solution {
2 public int sumSubarrayMins(int[] arr) {
3 int sum = 0, n = arr.length;
4 for(int i = 0; i < n; i++){
5 sum += arr[i];
6 int min_num = arr[i];
7 for(int j = i + 1; j < n; j++){
8 if(arr[j] > min_num){
9 sum += min_num;
10 }else{
11 sum += arr[j];
12 min_num = Math.min(min_num, arr[j]);
13 }
14 }
15 }
16 int MOD = 1_000_000_007;
17 return (int)(sum % MOD);
18 }
19 }

参考评论区的各位大佬,得到以下题解~

单调栈+贡献法:

①贡献法:

例如:[1,4,2,3,1]中2是子数组[2]、[4,2]、[2,3]、[4,2,3]的最小值,那么2对答案的贡献就是2*4 = 8。

由于以2为连续子数组中的最小值,那么连续子数组中就不能包含比2小的数,因此就可以找到2左右两侧比它小的数的下标,这样就可以确定以2为最小值的连续子数组的边界范围。左右两边比2小的边界范围在(0,4),闭区间为[1,3]。

设arr[i]对应的边界为开区间(L,R),子数组需要包含arr[i],故:

  • 左边的下标可以是:L, L+1, L+2,...,i,一共有i-L个;
  • 右边的下标可以是:i,i+1,i+2,...,R-1,一共有R-i个;

arr中不含重复元素的前提下,以arr[i]为最小值的数组个数为 (i-L)*(R-i) ,对答案的贡献值为 arr[i] *(i-L)*(R-i) (类比:上衣有n件,裤子有m条,则一共有 n * m中搭配方法)。注意:如果左侧没有比 arr[i]小的元素,则L= -1,如果右侧没有比 arr[i]小的元素,则R= n,

如果arr中包含重复元素,例如[1,2,4,2,3,1],第一个2和第二个2对应的边界为(0,5),都包含了子数组[2,4,2,3],这样就会计算同一个子数组。

这样需要修改一下边界的定义,将左边界改为小于等于arr[i]的元素下标,右边界依然为小于arr[i]的元素下标,那么:第一个2对应的边界为(0,5),第二个2对应的边界为(1,5)。

单调栈:参考@【爪哇缪斯L5】:https://leetcode.cn/problems/sum-of-subarray-minimums/solution/-by-muse-77-367z/

构建一个单调递增的栈,里面存放的是元素的下标,如果栈为空,那么直接入栈,如果栈不为空,则进行如下操作:

  • 如果 栈顶元素对应的值 >= arr[i]:就弹出栈顶元素,直到栈为空或者栈顶元素对应的值更小,此时栈顶就是最近更小值的位置,即为左边界,即(新的栈顶元素, i),反过来想想,对于每个出栈的元素,当前元素arr[i]就是向右比它更小的第一个元素,这样也就得到右边界(结合下面的图解进行理解);
  • 如果 栈顶元素对应的值 < arr[i]:则arr[i]直接入栈

例如:

当遍历完整个数组以后,栈中仍然还存在元素,让剩下元素出栈,根据题目中【提示】部分描述,1 <= arr[i] <= 3 * 10^4,所以,arr数组中所有元素都是大于0的,那么我们就虚拟一个元素将其放入堆栈中,因为堆栈中所有元素的值都大于0,所以也就都会被执行出栈操作了。

 java代码:

 1 class Solution {
2 private static final long MOD = 1000000007;
3 public int sumSubarrayMins(int[] arr) {
4 long ans = 0;
5 Deque<Integer> stack = new ArrayDeque<>();
6 //最左边界哨兵入栈,-1是索引
7 stack.push(-1);
8 for(int i = 0; i <= arr.length; i++){
9 //添加末尾哨兵,已经超过数组长度
10 //则设一个虚拟哨兵索引为n对应的值为0,方便剩余元素出栈
11 int m = i < arr.length ? arr[i] : 0;
12 while(stack.size() > 1 && arr[stack.peek()] >= m){
13 int r = stack.pop();
14 //当前栈顶的贡献值
15 //(栈顶-弹出后的栈顶)*(当前值的下标-弹出栈顶)
16 ans += (long) arr[r] * (r - stack.peek()) * (i - r);
17 }
18 stack.push(i);
19 }
20 return (int)(ans % MOD);
21 }
22 }

力扣907(java)-子数组的最小值之和(中等)的更多相关文章

  1. 【LeetCode】 907 子数组的最小值之和

    Decrisption Given an array of integers arr, find the sum of min(b), where b ranges over every (conti ...

  2. [Swift]LeetCode907. 子数组的最小值之和 | Sum of Subarray Minimums

    Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarra ...

  3. 力扣算法经典第一题——两数之和(Java两种方式实现)

    一.题目 难度:简单 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数, 并返回它们的数组下标. 你可以假设每种输入只会对应一 ...

  4. 力扣(LeetCode)15. 三数之和

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  5. 力扣(LeetCode)1.两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  6. [LeetCode] 907. Sum of Subarray Minimums 子数组最小值之和

    Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarra ...

  7. 152.Maximum Product Subarray---dp---连续子数组的最大乘积---《编程之美》2.13子数组的最大乘积

    题目链接:https://leetcode.com/problems/maximum-product-subarray/description/ 题目大意:给出一串数组,找出连续子数组中乘积最大的子数 ...

  8. N元数组的子数组之和的最大值

    题目:有N个整数的元素的一维数组,求子数组中元素之和中最大的一组(思想:动态规划) 分析: 设该数组为array[N], 那么对于array[i]该不该在元素之和最大的那个子数组中呢?首先,不如假设a ...

  9. [LeetCode] Continuous Subarray Sum 连续的子数组之和

    Given a list of non-negative numbers and a target integer k, write a function to check if the array ...

  10. 累加和为 K 的子数组问题

    累加和为 K 的子数组问题 作者:Grey 原文地址: 博客园:累加和为 K 的子数组问题 CSDN:累加和为 K 的子数组问题 题目说明 数组全为正数,且每个数各不相同,求累加和为K的子数组组合有哪 ...

随机推荐

  1. function 的入参 如果是指针的话,如果你用的好的话,会颠覆三观啊 这里就是指对象,数组不用考虑 // 夏娃的苹果

    function 的入参 如果是指针的话,如果你用的好的话,会颠覆三观啊 这里就是指对象,数组不用考虑 这就是一颗 夏娃的苹果

  2. @Autowired和@Resource整理

    参考,欢迎点击原文:https://www.ixigua.com/6991282608663593508?id=6945836219422999079&logTag=944f6616c791c ...

  3. HTML(html结构、标签导读 、路径))

    HTML第一天 我们接下来是进行的网页开发网页的相关概念: 什么是网页? 什么是HTML? 网页的形成? 一 什么是网页: 1.网站是指在因特网上根据一定的规则,使用 HTML 等制作的用于展示特定内 ...

  4. 单目测距那些事儿(上) | 从MobileEye谈起

    单目测距那些事儿(上) | 从MobileEye谈起 全面专业的自动驾驶学习资料:链接 前言 在ADAS领域,有个功能叫自适应巡航控制(Adaptive Cruise Control, ACC). A ...

  5. 三维模型OBJ格式轻量化的跨平台兼容性问题分析

    三维模型OBJ格式轻量化的跨平台兼容性问题分析 三维模型的OBJ格式轻量化在跨平台兼容性方面具有重要意义,可以确保模型在不同平台和设备上的正确加载和渲染.本文将分析OBJ格式轻量化的跨平台兼容性技术, ...

  6. 记录--前端路由 hash 与 history 差异

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 简单介绍 Vue Router Vue Router 是 Vue.js 官方的路由插件,它和 Vue.js 是深度集成的,适合用于构建单页 ...

  7. 记录-css实现交融文字效果

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 CSS是有魔法的,我们今天来实现一个CSS的动画效果,只需要几行代码就可以搞定. 第一步.我们要将一行文字从中间展开 <!DOCTY ...

  8. 一文搞懂idea中的根目录和路径(以Mybatis为例)

    一文搞懂idea中的根目录和路径(以Mybatis为例) 在 IntelliJ IDEA 中,项目结构和组织比较灵活,允许用户根据项目需求进行定制. 1.根目录概念: 1.1 项目根目录(Projec ...

  9. golang gc的内部优化

    今天讲一个常见的gc compiler(也就是官方版本的go编译器和runtime)在垃圾回收的扫描标记阶段做的优化. 我对这个优化的描述印象最深的是在bigcache的注释里,大致内容是如果map的 ...

  10. 主nginx和子nginx-------域名-端口-解答

    主nginx和子nginx-------域名-端口-解答 想象一下Nginx是一个接待员,每个端口就像接待员的一个电话线,而server_name就像是客户拨打的不同号码. 当你在Nginx配置文件里 ...