LeetCode152乘积最大子数组
方法一:动态规划
引出:根据经验[LeetCode53, 最大子序和],很容易推导出如下的状态转移方程:
但这样的推导是错误的?为什么呢?:不满足最优子结构
- 比如, 对应的, 其中的最大值为30, 很明显正确的答案应该是
如何 解决这个问题呢?从正负性角度出发来分析
- 如果当前值为正数,期望以它前一个位置结尾的某个段的积也是个正数,而且尽可能大。
- 如果当前值为负数,期望以它前一个位置结尾的某个段的积也是个负数,而且尽可能小(负数的绝对值越大)。
- 因此我们可以再维护一个,表示以第个元素为结尾的最小子数组的乘积,可以得到如下完整的动态规划转移方程,分别为取三个值的最值。
实现代码
class Solution {
public int maxProduct(int[] nums) {
if(nums == null || nums.length == 0){
return 0;
}
int length = nums.length;
int[] fmax = new int[length];
fmax[0] = nums[0];
int[] fmin = new int[length];
fmin[0] = nums[0];
int ans = fmax[0];
for(int i = 1; i <= length - 1; i++){
fmax[i] = Math.max(fmax[i-1] * nums[i], Math.max(fmin[i-1] * nums[i], nums[i]));
fmin[i] = Math.min(fmax[i-1] * nums[i], Math.min(fmin[i-1] * nums[i], nums[i]));
ans = Math.max(ans, fmax[i]);
}
return ans;
}
}
优化空间
第个状态之和第个状态相关,我们可以只用两个变量来维护时刻的状态,一个维护,一个维护
实现代码
public class Solution {
public double maxProduct(double[] arr) {
double res = Double.MIN_VALUE;
if(arr == null || arr.length == 0){
return res;
}
int len = arr.length;
double fmax = arr[0];
double fmin = arr[0];
res = fmax;
for(int i = 1; i < len; i++){
double newFmax = Math.max(Math.max(fmax * arr[i], fmin * arr[i]), arr[i]);
double newFmin = Math.min(Math.min(fmax * arr[i], fmin * arr[i]), arr[i]);
fmax = newFmax;
fmin = newFmin;
res = Math.max(res, fmax);
}
return res;
}
}