【动态规划】——最大子序和
今天总结一下有关动态规划问题中最大子序和的问题。
53.最大子数组和
题目要求给定一个数组,让我们求出最大连续子数组的和。我们使用动态规划来解决此类问题。
dp[i]表示以nums[i]结尾的连续子序列的和的最大值。那么我们要求的答案就是max{dp[i]}.其状态转移方程很容易就看出为dp[i]=max(dp[i],dp[i]+dp[i-1])。因为dp[i]需要尽可能的大,所以当dp[i-1]+dp[i]大于dp[i]时,我们更新dp[i]的值。代码如下:
class Solution { public: int maxSubArray(vector<int>& nums) { int n=nums.size(); vector<int> dp(nums); dp[0]=nums[0]; for(int i=1;i<n;i++){ dp[i]=max(dp[i],dp[i]+dp[i-1]); } int ans=*max_element(dp.begin(),dp.end()); return ans; } };
918.环形数组的最大和
这个题目题干给的很复杂,力扣官方的题解也不是写给人看的(至少我这种菜鸟完全看不懂写的什么天书)。但其实就是两种情况:
1、最大子数组和出现在数组内部:举个例子:
a1,a2,a3,(a4,...,ai,ai+1,ai+2,)...,an-1,an。其中a[4:i+2]就是我们所要求的和最大的子数组。这种情况与前面所述的最大子数组和问题一模一样。
2、最大子数组和出现在数组连接处:
(a1,a2,a3,a4),...,ai,ai+1,ai+2,...,(an-1,an),其中an-1,an,a1,a2,a3,a4即为我们所求。这个情况我们需要意识到一点:
数组和=最大子序列和+最小子序列和
上述式子其实很好理解:一个数组的和为Sn,其中最大的连续子序列和为An,由于数组为循环数组,首尾相接,剩下部分也是一个连续的子数组,这一部分的和Bn也就是整个数组的最小子序列和。因为如果Bn不是最小子序列和,那么从该子序列中还可以再分出一个子序列,这个子序列的和可以并入到最大的连续子序列和中。
理解到这一点,这题的代码就不难写出:
class Solution { public: int maxSubarraySumCircular(vector<int>& nums) { int n=nums.size(); vector<int> fMin(nums),fMax(nums); int sum=nums[0]; for(int i=1;i<n;i++){ fMin[i]=min(fMin[i],fMin[i]+fMin[i-1]); fMax[i]=max(fMax[i],fMax[i]+fMax[i-1]); sum+=nums[i]; } int maxV=*max_element(fMax.begin(),fMax.end()); int minV=*min_element(fMin.begin(),fMin.end()); return max(maxV,sum-minV==0?maxV:sum-minV); } };
152.乘积最大子数组
本题要求我们求给定数组的最大连续子序列的积。
此题的想法与918有相似之处:都需要维护两个数组fMax和fMin,其中一个是最大子序列积,一个是最小子序列积。其中最小子序列积一定是负的。因为这个题中有负数的存在,其不满足动态规划问题要求的最优子结构问题,举个例子:
例如【-2,3,-4】中,-4的最优解不是3*(-4),而是(-2)3(-4),所以我们需要分正负来讨论,多维护一个数组fMin,用来记录乘积的最小值(通常为负),当当前数字为负值时,可以调用fMin中记录的值来获得结果。
class Solution { public: int maxProduct(vector<int>& nums) { vector<int> fMax(nums),fMin(nums); for(int i=1;i<nums.size();i++){ fMax[i]=max(fMax[i],max(fMax[i]*fMax[i-1],fMax[i]*fMin[i-1])); fMin[i]=min(fMin[i],min(fMin[i]*fMin[i-1],fMin[i]*fMax[i-1])); } int ans=*max_element(fMax.begin(),fMax.end()); return ans; } };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了