给定一个整数数组 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 * 1041 <= arr[i] <= 3 * 104
题解:
/**
* @param {number[]} arr
* @return {number}
*/
// 方法一:暴力法 超时
var sumSubarrayMins = function (arr) {
let ans = 0
for (let i = 0; i < arr.length; i++) {
let min = arr[i]
for (let j = i; j < arr.length; j++) {
min = Math.min(min, arr[j])
ans = (ans + min) % 1000000007
}
}
return ans
};
// 方法二:单调栈
var sumSubarrayMins = function (arr) {
const mod = 1e9 + 7
let stack = []
// 当前值的左边界
let left = []
for (let i = 0; i < arr.length; i++) {
//这里的 arr[stack[stack.length - 1]] >= arr[i] 大于等于了,
后面的就只能是大于了,不然会重复计算相等的值
while (stack.length !== 0 && arr[stack[stack.length - 1]] >= arr[i]) stack.pop()
left[i] = stack.length ? stack[stack.length - 1] : -1
stack.push(i)
}
stack = []
// 当前值的右边界
let right = []
for (let i = arr.length - 1; i >= 0; i--) {
while (stack.length !== 0 && arr[stack[stack.length - 1]] > arr[i]) stack.pop()
right[i] = stack.length ? stack[stack.length - 1] : arr.length
stack.push(i)
}
let sum = 0
for (let i = 0; i < arr.length; i++) {
sum += (i - left[i]) * (right[i] - i) * arr[i]
sum %= mod
}
return sum
}
// 方法三:单调栈 + 动态规划
// 例: [3, 1, 2, 4]
// 可以归纳子数组为
// 3 1 + 1 1 + 1 + 2 1 + 1 + 2 + 4
// [3][1][2][4]
// [3, 1][1, 2][2, 4]
// [3, 1, 2][1, 2, 4]
// [3, 1, 2, 4]
// 单调栈初始:stock = [-1][-1, 0][-1, 1][-1, 2][-1, 3]
// 动态数组:[0, 0, 0, 0, 0]
// 总结规律dp[i + 1] = dp[stock[stock.length - 1] + 1] + (i - stock[stock.length - 1] * arr[i]
var sumSubarrayMins = function (arr) {
let stock = [],
dp = Array(arr.length + 1).fill(0),
res = 0,
m = 1e9 + 7
stock.push(-1)
for (let i = 0; i < arr.length; i++) {
while (stock[stock.length - 1] != -1 && arr[i] <= arr[stock[stock.length - 1]]) {
stock.pop()
}
dp[i + 1] = (dp[stock[stock.length - 1] + 1] + (i - stock[stock.length - 1]) * arr[i]) % m
stock.push(i)
res += dp[i + 1]
res %= m
}
return res
};
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。