[CP / Leetcode] 907. Sum of Subarray Minimums / 子数组的最小值之和
前言
接触 LeetCode 差不多有一个月了,按照专题断断续续做了八十几道题,虽然不多,但感觉确实有了很大的进步——从一开始的没有题解寸步难行,到现在能够完全独立做出那些从前 “完全无法想象的题目”,而本题就是其中之一。做过之后才发现,其实它并没有那么难。
分析
本题的关键词之一是 子数组。
首先考虑一个长度为
这一想法引导我们按照子数组的长度去枚举所有可能的子数组,这一做法的时间复杂度是
然而,“按照长度枚举子数组” 这一操作并不是很适合应用动态规划,所以我们需要思考另外一种枚举方法,它不仅要和前者一样,能够不重不漏的枚举所有可能的子数组,还要让动态规划更易于应用。
考虑以下的枚举方法:对于输入数组的每一个元素,枚举 以该元素为结尾 / 开头的所有子数组。以结尾为例,对于第一个元素来说,以它为结尾的子数组只有它自己;对于第二个元素来说,以它为结尾的子数组不仅有它自己,还有它和第一个元素共同构成的子数组……以此类推。
同样可以得到子数组总数为:
和第一种方法的不同之处在于,这一方法的每一步都是相似的。对于以第
这里的
回到本题。现在我们关注的是每个子数组的 最小值,也就是:
不妨考虑特殊情况,假设输入数组为
假设子数组集合
更一般化的,在枚举的过程中,对于每一个新考虑的元素
对于以
对于以
综上,有
上述操作可以用单调栈实现。
代码( )
class Solution { public: int sumSubarrayMins(vector<int>& arr) { int n = arr.size(); constexpr int mod = 1e9 + 7; int ans = 0; std::vector<int> dp(n); std::stack<int> monoStack; for (int i = 0; i < n; i++) { while (!monoStack.empty() && arr[i] < arr[monoStack.top()]) { monoStack.pop(); } if (monoStack.empty()) { dp[i] = (i + 1) * arr[i]; } else { int top = monoStack.top(); dp[i] = dp[top] + (i - top) * arr[i]; } ans = (ans + dp[i]) % mod; monoStack.push(i); } return ans; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)