lintcode-1734 · 子数组的最小值之和

举报
搞前端的半夏 发表于 2021/11/30 22:19:55 2021/11/30
【摘要】 描述给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。由于答案可能很大,因此模 10^9 + 7以后返回答案。**1 \leq A \leq 300001≤A≤300001 \leq A[i] \leq 300001≤A[i]≤30000样例样例 1:输入:[3,1,2,4]输出:17解释:子数组为 [3],[1],[2],[4],[3,1],...

描述

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

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

**

  • 1 \leq A \leq 300001≤A≤30000
  • 1 \leq A[i] \leq 300001≤A[i]≤30000

样例

样例 1:

输入:[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]。 
最小值为 3124112111,和为 17

样例 2:

输入:[95,58,46,67,100]
输出:859
解释:
子数组为 [95], [58], [46], [67], [100], [98,58], [58,46], [46,67], [67,100], [95,58,67],[46,67,100],[95,58,46,67],[58,46,67,100],[95,58,46,67,100]。 
最小值为 95, 58, 46, 67, 100, 58, 46, 46, 67, 46, 46, 46, 46, 46, 46,和为 859

题解

刚看到题目的时候,第一想法就是跑两个循环,找到所有的子数组,然后找到最小值。累计求和。不过这种方法的复杂度是0(n^2)。
首先我们观察一下题目中给出的结果:

对于[3,1,2,4]:
最小值是1:[1],[3,1],[3,1,2],[3,1,2,4],[1,2],[1,2,4]
最小值是2:[2], [2,4]

其实对于最小值来说,它所在数组的数量是可以计算出来的。
例如1:对于1来说,在元素组种,往左找第一个小于等于它的数字的的索引,没有的话返回-1,
往右找第一个小于它的数字的索引,没有返回数组长度。
最后是有计算公式的:(右索引-1的索引) *(1索引-左索引)

class Solution {
public:
/**
* @param A: an array
* @return: the sum of subarray minimums
*/
int sumSubarrayMins(vector<int> &A) {
// Write your code here.
int res = 0, n = A.size(), mod = 1e9 + 7, j, k;
stack<int> s;
for (int i = 0; i <= n; ++i) {
while (!s.empty() && A[s.top()] > (i == n ? 0 : A[i])) {
j = s.top(), s.pop();
k = s.empty() ? -1 : s.top();
res = (res + A[j] * (i - j) * (j - k)) % mod;
}
s.push(i);
}
return res;
}
};


【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。