Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
开启新一轮的卷啦 ~
题目:给定一个数组nums,要求找出该数组中乘积最大的非空连续子数组,并且返回该子数组对应的乘积。
解题思路
本题的第一印象就是 LeetCode 53最大子数组和 ,和本题的区别只要加变成了乘,动态规划的转移方程都是:
于是按照该题的思路可得到如下代码:
public int maxProduct(int[] nums) {
int max=nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
for(int i=1;i<nums.length;i++){
dp[i] = Math.max(dp[i-1]*nums[i], nums[i]);
max = Math.max(max, dp[i]);
}
return max;
}
不出意外报错了,我们可以想象一个数组[-4, -1, -2, -3],当数组遍历到-2之前,系统保存的最大值是4,而dp[i-1]保存的是4,到了-2这个索引的时候,则dp[i]变成了-2,max还是4,按照循环完成,最终保存的最大值也就是6,但实际最大值是24,这是因为我们只保存了最大值,而在遍历到负数的时候,最大值就变成了最小值,当再次遇到负数就丢失了使最小值变成最大值的机会。
因此我们在本题中不仅要保存最大值还需要保存最小值,在每次判断时候需要判断最小值可不可能成为最大值,可得代码如下:
public int maxProduct(int[] nums) {
int[] maxProduct = new int[nums.length];
int[] minProduct = new int[nums.length];
maxProduct[0] = nums[0];
minProduct[0] = nums[0];
for(int i=1;i<nums.length;i++){
maxProduct[i] = Math.max(maxProduct[i-1]*nums[i], Math.max(minProduct[i-1]*nums[i], nums[i]));
minProduct[i] = Math.min(minProduct[i-1]*nums[i], Math.min(maxProduct[i-1]*nums[i], nums[i]));
}
int max = Integer.MIN_VALUE;
for(int j=0;j<maxProduct.length;j++){
max = Math.max(max, maxProduct[j]);
}
return max;
}
上述代码的时间复杂度和空间复杂度都是。对于动态规划一般都可以对空间复杂度进行优化,本题也不例外,一般就是将前一个状态保存赋给下一个状态即可,可得如下代码:
public int maxProduct(int[] nums) {
int maxProduct = nums[0];
int minProduct = nums[0];
for(int i=1;i<nums.length;i++){
// 我们需要记录上一个状态,此方式无法记录
maxProduct = Math.max(maxProduct*nums[i], Math.max(minProduct*nums[i], nums[i]));
minProduct = Math.min(minProduct*nums[i], Math.min(maxProduct*nums[i], nums[i]));
}
return maxProduct;
}
但本题不能使用这种方法,仔细看循环中,两个变量是同时更新的,也就是没有顺序,但上述代码会先更新maxProduct,而在minProduct的计算中用到了maxProduct,因此会报错,此时需要使用两个变量记录一下前一个状态,修改代码如下:
public int maxProduct(int[] nums) {
int maxProduct = nums[0];
int minProduct = nums[0];
int maxAns = nums[0];
for(int i=1;i<nums.length;i++){
int maxPre = maxProduct;
int minPre = minProduct;
maxProduct = Math.max(maxPre*nums[i], Math.max(minPre*nums[i], nums[i]));
minProduct = Math.min(minPre*nums[i], Math.min(maxPre*nums[i], nums[i]));
maxAns = Math.max(maxAns, maxProduct);
}
return maxAns;
}
上述代码时间复杂度为,空间复杂度为。