给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:
输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组
思路:
本题是求最大乘积,是最大子段和的变种。最大乘积可以由 正数*正数 和 负数*负数得到,因此,需要同时记录下最大值和最小值。 状态转移方程:
动态规划:
数组max[i] 以当前元素i结尾的最大乘积
数组min[i] 以当前元素i结尾的最小乘积
//以当前元素结尾的乘积最大子数组的乘积
public int maxProduct(int[] nums) {
if (nums == null)
return 0;
int res = nums[0];
//以当前元素结尾的最大乘积
int[] max = new int[nums.length];
//以当前元素结尾的最小乘积
int[] min = new int[nums.length];
max[0] = min[0] = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] >= 0) {
max[i] = Math.max(nums[i], max[i - 1] * nums[i]);
min[i] = Math.min(nums[i], min[i - 1] * nums[i]);
} else {
max[i] = Math.max(nums[i], min[i - 1] * nums[i]);
min[i] = Math.min(nums[i], max[i - 1] * nums[i]);
}
res = Math.max(res, max[i]);
}
return res;
}
动态规划,节约空间只用两个变量表示第 i个元素结尾的乘积最大子数组的乘积(也就是以当前位置为结尾),再遍历的过程中去更新res
res= max(max*nums[i],min*nums[i],dp[i-1])
max = max(max*nums[i],min*nums[i],nums[i])
min = min(max*nums[i],min*nums[i],nums[i])
public int maxProduct(int[] nums) {
if (nums == null || nums.length == 0)
return 0;
int n = nums.length;
int res = nums[0];
int max = nums[0];
int min = nums[0];
for (int i = 1; i < n; i++) {
if (nums[i] >= 0) {
max = Math.max(nums[i], nums[i] * max);
min = Math.min(nums[i], nums[i] * min);
} else { //当前数为负数
int tmp = max; //报存最大值
//负数乘以最小的等于最大的
max = Math.max(nums[i], nums[i] * min);
min = Math.min(nums[i], nums[i] * tmp);
}
res = Math.max(res, max);
}
return res;
}