多的不说了,和前几天的差不多,直接上题。
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
暴力:
class Solution {
public:
int maxProduct(vector<int>& nums) {
int len=nums.size();
int pro=nums[0];
for(int i=0;i<len;i++)
{
int p=1;
for(int j=i;j<len;j++)
{
p*=nums[j];
if(pro<p)
pro=p;
}
}
return pro;
}
};
动态规划:
其实整个乘积数组难就难在负数部分,我们之前的正数在遇到负数后就会变成最小,但是如果后面有负数出现,就又会把结果变成最大。
所以,我们申请两个数组来存取到当前位置的最大值和当前位置的最小值,也就是正数数组将整数变负前的正数存储下来,负数数组把负的数组保存下来,0的情况可涵盖在其中。
但其实我们的乘积是无后效性的,也就是说i位置只和i-1位置的结果有关,所以我们不需要申请一个数组,只需要申请两个数存取i-1的结果就行。
代码就出来了。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int len=nums.size();
int maxp=nums[0],minp=nums[0],pro=nums[0];
for(int i=1;i<len;i++)
{
int mx=maxp,mi=minp;//因为之后会先更新maxp,所以minp会用更新后的,因此需要提前保存好之前的大小
maxp=max(mx*nums[i],max(mi*nums[i],nums[i]));//最大更新、最小更新、此数
minp=min(mi*nums[i],min(mx*nums[i],nums[i]));//最小更新、最大更新、此数
pro=max(maxp,pro);//更新结果
}
return pro;
}
};
动态规划需要辅助数组来保存结果,上述情况则可以节省空间,因为每一个状态方程只和上一个状态有关,所以只需要保存上个结果即可。也就是无后效性。
数学辅助
这个是我第一下就想起来的方法。
乘积的变化无非是三种情况:
- 全正数,越大越好。
- 有奇数个负数则为负,偶数个则为正,所以要保证数组内是偶数个负数。
- 0,数组内不含0,因为0会让所有的结果失效。
所以,我们将数相乘,用一个数来保存最大结果,随着乘积更新。数组我们以0为分界线,划分为数个子数组,重复上述方法。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int len=nums.size();
int maxr=nums[0];
int pro=1;
for(auto a:nums)
{
pro*=a;
maxr=max(maxr,pro);
if(pro==0)
pro=1;
}
pro=1;
for(int i=len-1;i>=0;i--)
{
pro*=nums[i];
maxr=max(maxr,pro);
if(pro==0)
pro=1;
}
return maxr;
}
};
还是那句话,数学是基础,编程是工具。
加油。