时间:2019.6.5(周三)
题目描述:给定一个整数数组 nums ,输出乘积最大的连续子序列(该序列至少包含一个数)的值。原题链接
难度等级:Medium
思路一:双重遍历暴力求解。遍历到 i,都和 i 之前的再循环一遍,找到最大值。这种解法会超时。
思路二:动态递归。考虑利用之前的遍历结果。求乘积最大的连续子序列,最麻烦之处在于:(1)当遇到0的时候,整个乘积会变成0;(2)当遇到负数的时候,当前的最大乘积会变成最小乘积,最小乘积会变成最大乘积。所以创建两个数组保存最大值和最小值,
- 当前的最大值等于已知的最大值、最小值和当前值的乘积,当前值,这三个数的最大值。
- 当前的最小值等于已知的最大值、最小值和当前值的乘积,当前值,这三个数的最小值。
结果是最大值数组中的最大值。
public int maxProduct(int[] nums) {
if (nums.length == 0) return 0;
if (nums.length == 1) return nums[0];
int[] max = new int[nums.length];
int[] min = new int[nums.length];
int retVal;
resVal= max[0] = min[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
max[i] = Math.max(nums[i], Math.max(nums[i] * max[i - 1], nums[i] * min[i - 1]));
min[i] = Math.min(nums[i], Math.min(nums[i] * max[i - 1], nums[i] * min[i - 1]));
resVal= Math.max(resVal, max[i]);
}
return resVal;
}
数组可以进一步优化成 int,空间复杂度从O(n) -> O(1)。
class Solution {
public int maxProduct(int[] nums) {
if(nums.length == 0)
return 0;
if(nums.length == 1)
return nums[0];
int max, min, preMax, preMin, resVal;
resVal = max = min = nums[0];
for(int i = 1; i < nums.length; i++) {
preMax = max;
preMin = min;
max = Math.max(nums[i], Math.max(nums[i] * preMax, nums[i] * preMin));
min = Math.min(nums[i], Math.min(nums[i] * preMax, nums[i] * preMin));
resVal = Math.max(max, resVal);
}
return resVal;
}
}
时间复杂度:O(n),只遍历一次
空间复杂度:O(1),使用恒定的额外空间