这两道算法题的解题思路是差不多的,但是从整体上分析,乘积最大子序列之和是最大子序和的进阶。先来看看两道算法题的简单描述。
53.最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
简单分析:
作者:liweiwei1419
链接:https://leetcode-cn.com/problems/maximum-subarray/solution/dong-tai-gui-hua-fen-zhi-fa-python-dai-ma-java-dai/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
——————————————————————————————————————————
53.最大子序和的代码:
个人觉得,在动态规划问题中,定义好状态和状态转移方程是最难了。找到了合适的状态转移方程,写代码就比较简单了。对于该题,最巧妙的就是dp[i]表示的是以nums[i]结尾的最大连续子数组之和,而不是表示nums[0]到nums[i]的最大子序列之和。后者设定的状态很难找到状态转移方程,而前者的状态可以很轻松找到状态转移方程。具体的C++代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int length = nums.size();
vector<int> dp(length,0);
dp[0] = nums[0];
int num = dp[0];
for(int i=1;i<length;i++)
{
if(dp[i-1]>=0) //如果dp[i-1]大于零,则无论当前nums[i]的值大于零还是小于零,都可以直接加上,因为一个数加上一个正数,肯定是大于这个数的
dp[i] = dp[i-1] + nums[i];
else
dp[i] = nums[i]; //如果dp[i-1]小于零,则另起炉灶,因为一个数加上一个负数,无论如何都是小于这个数的
num = max(num,dp[i]);
}
return num;
}
};
——————————————————————————————————————————
152. 乘积最大子序列
给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
解题思路
这道题的解题方法和前面那道题是一样的。但是为什么是进阶呢?进阶的地方就在于不是加法而是乘法。考虑一下,在加法中,一个数(不管是正负),加上一个正数,其值必定比原来大。当加上一个负数时,其值必定比原来的小。
但是在乘法运算中,一个正数,乘于一个正数(正整数,大于等于)时,其值至少大于等于原来的值。一个负数,乘于一个正数时,其值却比原来的更小,这个地方,就是乘法和加法的区别。在加法中,一个负数加上一个正数,其值必定大于原来的值。同理,一个负数乘于一个负数,最后的结果是一个正数,这也是和加法是有区别的。这就是需要考虑的地方,需要分类讨论。当nums[i]的值和dp[i-1]的值的正负关系不同的时候,状态转移方程怎么写。
其C++代码如下:
class Solution {
public:
int maxProduct(vector<int>& nums) {
int length = nums.size();
vector<int> maxl(length,0); //用于存储nums[i]结尾的当前最大值
vector<int> minl(length,0); //用于存储nums[i]结尾的当前最小值
maxl[0] = nums[0]; //初始化为nums[0];
minl[0] = nums[0]; //初始化为nums[0];
int num = nums[0]; //最后返回的乘积最大子序列的值
for(int i=1;i<length;i++)
{
if(nums[i]>0) //当nums[i]大于零时,不论前面的dp[i-1]大于零还是小于零,大于零的必定更大,小于零的必定更小
{
maxl[i] = max(nums[i],nums[i]*maxl[i-1]);
minl[i] = min(nums[i],nums[i]*minl[i-1]);
}
else if(nums[i]<0) //当nums[i]小于零时,dp[i-1]小于零时变为大于零,dp[i-1]大于零时变为小于零
{
maxl[i] = max(nums[i],nums[i]*minl[i-1]);
minl[i] = min(nums[i],nums[i]*maxl[i-1]);
}
else //当nums[i]的值为零时,最大和最小值都是0
{
manl[i] = 0;
minl[i] = 0;
}
num = max(num,maxl[i]); //存储当前的最大序列乘积值
}
return num;
}
};