152-乘积最大子数组

152-乘积最大子数组

力扣152

https://leetcode-cn.com/problems/maximum-product-subarray/

这题不是普通的动态规划题,借助了最大最小两个数组来进行动态规划

动态规划解法可以参考官方题解

https://leetcode-cn.com/problems/maximum-product-subarray/solution/cheng-ji-zui-da-zi-shu-zu-by-leetcode-solution/


在评论区看到一个很妙的思路,动态规划的关键在哪里?关键就在于

只要相乘不为0,绝对值就会增大。如果数组的数是负数,那么会导致最大的变最小的,最小的变最大的,最大最小保存起来交换即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int maxProduct2(int[] nums) {
int max = Integer.MIN_VALUE, imax = 1, imin = 1; //一个保存最大的,一个保存最小的。
for(int i=0; i<nums.length; i++){
if(nums[i] < 0){ //如果数组的数是负数,那么会导致最大的变最小的,最小的变最大的。因此交换两个的值。
int temp = imax;
imax = imin;
imin = temp;
}
imax = Math.max(imax*nums[i], nums[i]);
imin = Math.min(imin*nums[i], nums[i]);
max = Math.max(max, imax);
}
return max;
}

太强了,这辈子想不出了…


不过这道题可以有一个更加容易思考的解法:

记录一个当前乘积product,一个当前最大max

1如果有0,则会以0为分界点,将product重置为1重新计算

2如果没有0,分为两种情况:

2.1负数为偶数,一直乘到底

2.2负数为奇数,从左边开始乘到最后一个负数前有一个最大值,从右边开始乘也有一个最大值,比较即可

明白了这一点后可以简化:

2.2中所说“最后一个负数前”其实不需要考虑,直接乘到底,因为我们记录了max,就算乘到底也不会比max大(负数<正数)

2.1可以包含在2.2中,只不过左右两次结果一样罢了

1可以包含在2.2中,只需要判断当前是否为0重置product即可

所以代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public int maxProduct(int[] nums) {
int product = 1;
int max = nums[0];
//从左往右
for (int i = 0; i < nums.length; i++) {
product *= nums[i];
max = Math.max(max, product);
if (nums[i] == 0) product = 1;
}
//从右往左
product = 1;
for (int i = nums.length - 1; i >= 0; i--) {
product *= nums[i];
max = Math.max(max, product);
if (nums[i] == 0) product = 1;
}
return max;
}

其他动态规划的题目可以点击这里

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×