题目链接
https://leetcode-cn.com/problems/maximum-product-subarray/
题目描述
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子数组 [2,3] 有最大乘积 6。 示例 2: 输入: [-2,0,-1] 输出: 0 解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
解题思路
1.暴力枚举
双重for循环,以数组中每个下标开始,迭代更新乘积最大的连续子数组。时间复杂度O(n2)
2.动态规划
首先本题与LC 53.最大子序和类似,53题的转移方程为dp[i]=max(dp[i-1]+nums[i],nums[i]),dp[i]仅仅与前一个状态有关,因为题目要求是连续子数组。回到本题中,如果只考虑数组中只会出现正数,那么这道题就和53题的思路是一样的,状态转移方程也是一样的:dp[i]=max(dp[i-1]*nums[i],nums[i]),但是本题中数组中是会出现不定个数的负数,如果只有一个负数,上述状态转移方程是没有问题的,但是如果出现两个负数就会产生问题,因为负负得正,比如数组[2,3,-3,-4]。,那么第一个符号之前所有的乘积就都要考虑在dp[i]里面,但是用上述方程,早在第一个负数出现的时候,它前面的乘积都已经丢掉了,所以这才是为什么还需要记录一个最小值,说白了,最小值只有是负数出现的时候才会在这道题发挥它的用处,否则,最小值和最大值都是一样的。所以对于dp[i]来说,dp[i-1]可能是最大值也可能是最小值,若nums[i]>0,则dp[i-1]记录的是>0的最大值,则没问题,若nums[i]<0,dp[i-1]就应该记录的是<0的最小值,这样才能产生最大值。所以改进后的状态转移方程如下:
maxF[i] = max(minF[i - 1] * nums[i], max(nums[i], maxF[i - 1] * nums[i]));
minF[i] = min(maxF[i - 1] * nums[i], min(nums[i], minF[i - 1] * nums[i]));
AC代码
1.暴力枚举(超时)
1 class Solution { 2 public: 3 int maxProduct(vector<int>& nums) { 4 int ans = INT_MIN; 5 for(int i = 0; i < nums.size(); i++) 6 { 7 int val = 1; 8 for(int j = i; j < nums.size(); j++) 9 { 10 val = val * nums[j]; //迭代更新乘积最大的连续子数组 11 if(val > ans) ans = val; //迭代更新乘积最大的连续子数组 12 } 13 } 14 return ans; 15 } 16 };
2.动态规划
1 class Solution { 2 public: 3 int maxProduct(vector<int>& nums) { 4 vector <int> maxF(nums), minF(nums); 5 int ans = max(INT_MIN,nums[0]); 6 for (int i = 1; i < nums.size(); ++i) { 7 maxF[i] = max(minF[i - 1] * nums[i], max(nums[i], maxF[i - 1] * nums[i])); 8 minF[i] = min(maxF[i - 1] * nums[i], min(nums[i], minF[i - 1] * nums[i])); 9 ans = max(ans,maxF[i]); 10 } 11 return ans; 12 } 13 };
因为当前状态只有前一个状态有关,所以可以把空间复杂度从O(n)优化至O(1)
优化后的动态规划
1 class Solution { 2 public: 3 int maxProduct(vector<int>& nums) { 4 int maxf = 1; 5 int minf = 1; 6 int ans = INT_MIN; 7 for(int i = 0; i < nums.size(); i++) 8 { 9 int aa = maxf; //利用aa记录尚未更新的maxf的值。 10 maxf = max(minf*nums[i],max(maxf*nums[i],nums[i])); 11 minf = min(aa*nums[i],min(minf*nums[i],nums[i])); 12 ans = max(ans,maxf); 13 } 14 return ans; 15 } 16 };