解题思路:
最原始的想法就是枚举起点终点,然后遍历乘一遍。最终MAX就是答案。
但是这个做法的复杂度达到了O(n^3),很难接受,所以有dp的解法。
dp分析:
考虑集合的表示:
f[i], g[i]
f[i]表示以i为终点,左侧连续且乘积最大的值是多少
g[i]表示以i为终点,左侧连续且乘积最小的值是多少
因为在枚举终点,最优解一定是某个终点向左连续乘积得到的,所以一定可以得到答案。所以f[k]之中最大的那个就是答案。
考虑状态的计算:
我们有了f[i-1], g[i-1],要想办法求出f[i], g[i]
因为左侧都是连续的,所以以第i位结尾的只有三种情况:
- 不要前面的数,自己本身,即nums[i]
- 如果nums[i]>0,最大值应该是nums[i] * f[i],最小值应该是nums[i] * g[i]
- 如果nums[i]<0,最大值应该是nums[i] * g[i],最小值应该是nums[i] * f[i]
本身是正数,不管f[i-1]和g[i-1]是正还是负,肯定要乘最大的才能获得到最大值。负数同理。可以自己找几个数试一下。
根据定义我们只需要把nums[i],nums[i] * f[i],nums[i] * g[i]算出来
最大的就是f[i],最小的就是g[i]
然后找出f的最大值返回即可
我们可以优化空间,因为只和上一位有关,所以数组用一个数记录上一位的f和g即可,每次res和f取一下max。
代码实现:
class Solution {
public int maxProduct(int[] nums) {
int len = nums.length;
int f = nums[0], g = nums[0];
int res = f;
for (int i = 1; i < len; i ++ ) {
int a = nums[i] * f;
int b = nums[i] * g;
f = Math.max(nums[i], Math.max(a, b));
g = Math.min(nums[i], Math.min(a, b));
res = Math.max(res, f);
}
return res;
}
}