https://leetcode-cn.com/problems/maximum-product-subarray
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个32位整数。
思路:
在乘法中,两个负数相乘会得到正数,而负数乘正数会得到负数,也就是说,有可能上一个积是最大值,下一个就变成了最小值。所以需要记录每一次乘积的最大值和最小值。
状态定义:dp[i][0]表示从0-i子数组的最小乘积,dp[i][1]表示0到i子数组的最大乘积。
那么想要推断二者的状态转移方程,需要从三种情况考虑:
最小乘积:
- num[i]是正数,乘上前一个状态的最小积可以得到最小积
- num[i]是负数,乘上前一个状态的最大积可以得到最小积
- num[i]本身最小
- 状态方程: dp[i] [0]=min(dp[i−1] [0]∗num[i] , dp[i−1] [1] ∗ num[i], num[i])
最大乘积
- num[i]是正数,乘上前一个状态的最大积可以得到最大积
- num[i]是负数,乘上前一个状态的最小积可以得到最大积
- num[i]本身最大
- 状态方程:dp[i] [1]=max(dp[i−1] [0]∗num[i] , dp[i−1] [1] ∗ num[i], num[i])
var maxProduct = function(nums) {
const len = nums.length;
let dp = new Array(len).fill(0).map( () => new Array(2).fill(0) );
let result = nums[0];
dp[0][0] = nums[0]; //min
dp[0][1] = nums[0]; //max
for (let i = 1; i < len; i++) {
dp[i][0] = Math.min(dp[i-1][0] * nums[i], dp[i - 1][1] * nums[i], nums[i]);
dp[i][1] = Math.max(dp[i-1][1] * nums[i], dp[i - 1][0] * nums[i], nums[i]);
result = Math.max(result, dp[i][1]);
}
return result
};
通过上述可知,dp[i][0]和dp[i][1]可以用两个变量表示,即状态可压缩
var maxProduct = function(nums) {
const len = nums.length;
let result = nums[0];
min = nums[0]; //min
max = nums[0]; //max
for (let i = 1; i < len; i++) {
let temp = min;
min = Math.min(min * nums[i], max * nums[i], nums[i]);
max = Math.max(max * nums[i], temp * nums[i], nums[i]);
result = Math.max(result, max);
}
return result
};