152. Maximum Product Subarray(动态规划)
Given an integer array nums
, find the contiguous subarray within an array (containing at least one number) which has the largest product.
Example 1:
Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.
Example 2:
Input: [-2,0,-1] Output: 0 Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
由于负数的存在,需要同时保存当前最大值和当前最小值,所以需要维护两个DP表,可以分别表示为dp_min和dp_max。所以即为dp_max里的最大值。
需要维护的当前最大值和当前最小值,都是在dp_min[i-1] * A[i],dp_max[i] * A[i],和A[i]这三者里面取一即可。有了这个只关乎最终状态,不关乎过程细节的结论,解题过程可以大大简化。
class Solution: def maxProduct(self, nums: List[int]) -> int: n = len(nums) dp_max = nums.copy() dp_min = nums.copy() for i in range(1,n): dp_max[i] = max(nums[i],dp_max[i-1]*nums[i],dp_min[i-1]*nums[i]) dp_min[i] = min(nums[i],dp_max[i-1]*nums[i],dp_min[i-1]*nums[i]) return max(dp_max)
1 class Solution { 2 public: 3 int maxProduct(vector<int>& nums) { 4 int n = nums.size(); 5 if(n==0) return 0; 6 vector<int>dp_max(n,nums[0]); 7 vector<int>dp_min(n,nums[0]); 8 9 int res_val = nums[0]; 10 for(int i =1;i<n;i++){ 11 dp_max[i] = std::max( std::max(dp_max[i-1]*nums[i],dp_min[i-1]*nums[i]), nums[i]); 12 dp_min[i]= std::min( std::min(dp_min[i-1]*nums[i],dp_max[i-1]*nums[i]), nums[i]); 13 14 } 15 for(int i =0;i<n;i++) 16 res_val = std::max(dp_max[i],res_val); 17 return res_val; 18 19 } 20 };
思考以上DP解法的空间开销过大的原因,是因为保存了整个DP表。其实整个过程中,获得dp[i]的值只需要dp[i-1]的值,所以是不需要保存整个DP表的。
这样一来,DP可以用滚动数组进行优化。简单的写法其实就是设一对prevMin/prevMax表示上一个值,以及还有一对curMin/curMax表示当前值。
1 class Solution { 2 public: 3 int maxProduct(vector<int>& nums) { 4 int n = nums.size(); 5 if(n==0) return 0; 6 int dp_max_pre = nums[0]; 7 int dp_min_pre = nums[0]; 8 int dp_max; 9 int dp_min; 10 11 int res_val = nums[0]; 12 for(int i =1;i<n;i++){ 13 dp_max = std::max( std::max(dp_max_pre*nums[i],dp_min_pre*nums[i]), nums[i]); 14 dp_min= std::min( std::min(dp_max_pre*nums[i],dp_min_pre*nums[i]), nums[i]); 15 res_val =std::max(res_val,dp_max); 16 dp_max_pre = dp_max; 17 dp_min_pre = dp_min; 18 } 19 20 return res_val; 21 22 } 23 };