We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
题:
给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
输入:[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 <= A <= 30000 1 <= A[i] <= 30000
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/sum-of-subarray-minimums 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解:此题暴力解法不难,难得是线性复杂度条件下解决问题。
// 暴力求解,临近超时边缘 var sumSubarrayMins = function(A) { const bigPrimeNumber = 10 ** 9 + 7 // 「循环不变式」所需要的变量 let stackTop = 0 // 存储答案 let ans = 0 for (let i = 0; i < A.length; i++) { for (let j = i; j < A.length; j++) { // 子数组长度为 1 时,将子数组首元素直接入栈 if (j === i) { stackTop = A[j] // 子数组长度大于 1 时,将子数组的最小值入栈 } else { stackTop = Math.min(stackTop, A[j]) } // 更新 ans ans += stackTop } } // 循环终止,返回答案 return ans % bigPrimeNumber };
下面这个线性复杂度解法是利用单调递增栈,总共需要维护 四个「循环不变式」 相关的变量。一般题目也就两三个,此题一共四个,而且思路巧妙。突破点是意识到对数组中的每一个元素进行计数,然后利用单调递增栈更新和维护计数,同时累计子数组最小元素之和。
// 线性复杂度:单调递增栈 var sumSubarrayMins = function(A) { const bigPrimeNumber = 10 ** 9 + 7 // 外层 for「循环不变式」相关的变量 const stack = [] let minSoFar = 0 let subMinSoFar = 0 for (let y of A) { // 内层 while「循环不变式」相关的变量,初始值为 1 let countY = 1 // 更新单调递增栈,保证「循环不变式」 while (stack.length && stack[stack.length - 1][0] >= y) { // 弹出不再单调递增的部分 const [x, c] = stack.pop() // 更新 countY: 弹出的 count 都应该归到当前元素 y 上 countY += c // 更新 subMinSoFar: 将出栈部分剔除 subMinSoFar -= x * c } // 内层 while 循环终止:将当前元素以及对应的 count 入栈 stack.push([y, countY]) // 更新 subMinSoFar: 计入入栈部分 subMinSoFar += y * countY // 将当前稳定的 subMinSoFar 计入到总的 minSoFar minSoFar += subMinSoFar } // 外层循环终止:对大素数取模之后得到目标解 return minSoFar % bigPrimeNumber }
补充前驱递减数组(使用正向递增栈求解)和后继递增数组(使用反向递增栈求解)的方法
// Prev / Next Array var sumSubarrayMins = function(A) { const bigPrimeNumber = 10 ** 9 + 7 // 数组的左右边界 const [lo, hi] = [-1, A.length] // 从左到右递增栈(记录索引) const stack = [] const prev = Array(hi).fill(lo) for (let i = 0; i < hi; i++) { while (stack.length && A[i] <= A[stack[stack.length - 1]]) stack.pop() if (stack.length) prev[i] = stack[stack.length - 1] stack.push(i) } // 从右到左递增栈(记录索引) stack.length = 0 const next = Array(hi).fill(hi) for (let k = hi - 1; k >= 0; k--) { while (stack.length && A[k] < A[stack[stack.length - 1]]) stack.pop() if (stack.length) next[k] = stack[stack.length - 1] stack.push(k) } // sum{A[i] * (left[i] + 1) * (right[i] + 1)} (lo < i < hi) let min = 0 for (let i = lo + 1; i < hi; i++) { min += (i - prev[i]) * (next[i] - i) * A[i] } return min % bigPrimeNumber }
The text was updated successfully, but these errors were encountered:
No branches or pull requests
题:
给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
输入:[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 <= A <= 30000
1 <= A[i] <= 30000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sum-of-subarray-minimums
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解:此题暴力解法不难,难得是线性复杂度条件下解决问题。
下面这个线性复杂度解法是利用单调递增栈,总共需要维护 四个「循环不变式」 相关的变量。一般题目也就两三个,此题一共四个,而且思路巧妙。突破点是意识到对数组中的每一个元素进行计数,然后利用单调递增栈更新和维护计数,同时累计子数组最小元素之和。
补充前驱递减数组(使用正向递增栈求解)和后继递增数组(使用反向递增栈求解)的方法
The text was updated successfully, but these errors were encountered: