Find the contiguous subarray within an array (containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4]
,
the contiguous subarray [2,3]
has the largest product = 6
.
public int maxProduct(int[] nums)
这题不好和前面max sum的题一样用前缀法,因为乘法特殊,如果乘了0就把以前以后的信息都消去了,如0,1,1,2,3,4,5,4,3,乘后全是0,无法用两者相除来得到这一段区间的乘积信息
算法:小DP。max[], min[]定义是从这个点开始向前连续任意长度的数组乘积最大值最小值。最后不是返回max[length - 1],而是返回过程中打擂台胜出的值。这样又可以做到允许间断(打擂台),又可以做到轻松地写出状态转移方程(因为你加了存储的值是连续的这个限制)。
细节:1.乘法和当前数是正数负数还是0有关,正数的话当前连续最大值是max[i] = nums[i] * max[i - 1],负数的话是max[i] = nums[i] * min[i - 1],零的话连续肯定0。这点小心。
2.可以做一个空间变O(1)的优化,因为每次计算只和前一个有关,没必要全纪录下来,所以用min,max,minPre,maxPre,result即可,不过这里pre不是说前缀,只是前一个的意思。
1.O(n)空间
class Solution { public int maxProduct(int[] nums) { int[] max = new int[nums.length]; int[] min = new int[nums.length]; max[0] = min[0] = nums[0]; int result = nums[0]; for (int i = 1; i < nums.length; i++) { if (nums[i] > 0) { max[i] = Math.max(nums[i], nums[i] * max[i - 1]); min[i] = Math.min(nums[i], nums[i] * min[i - 1]); } else if (nums[i] < 0) { max[i] = Math.max(nums[i], nums[i] * min[i - 1]); min[i] = Math.min(nums[i], nums[i] * max[i - 1]); } result = Math.max(result, max[i]); } return result; } }
2.O(1)空间
class Solution { public int maxProduct(int[] nums) { if (nums == null || nums.length == 0) { return 0; } int preMax = nums[0], preMin = nums[0]; int max = nums[0], min = nums[0]; int result = nums[0]; for (int i = 1; i < nums.length; i++) { if (nums[i] > 0) { max = Math.max(nums[i], nums[i] * preMax); min = Math.min(nums[i], nums[i] * preMin); } else if (nums[i] < 0) { max = Math.max(nums[i], nums[i] * preMin); min = Math.min(nums[i], nums[i] * preMax); } else { max = min = 0; } result = Math.max(result, max); preMax = max; preMin = min; } return result; } }