问题描述:
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.
题目大致的意思是给你一个数组,要你算连续的子数组乘积的最大值。
一开始看到这道题,很容易就想到暴力拆解的方法,但是说实话,这样子处理起来时间复杂度很高,肯定是不行的。再仔细想想,就想到了动态规划的想法了。很明显在这种数组中求子数组求和或者求积的最大值的题中,肯定是要有个变量来保存最大值,以及有其他变量来在遍历的过程中保存中间值的,这道题就是一个很经典的例子。
数组中只有整数,那就是负整数、正整数还有0三种。如果对数组进行遍历,会遇到这三种数,就对应三种情况吧:
①正整数:正整数×正整数=更大的正整数,而正整数×负整数=更小的负整数这个没问题。
②负整数:负整数×正整数=更小的负整数,而负整数×负整数=更大的正整数。负整数的存在,就意味着我们不可能只需要一个max的中间变量就搞定,而需要一个min,因为无论如何,min×负整数肯定是大于max×正整数的(先排除0的情况),所以我们需要两个中间变量:max、min。
③0:呃,0的出现,让情况变得复杂了许多。无论你min或max是什么,最后×0一定是0,那么如果你后面遍历时还把后面的元素算进前面这个子数组时,已经没有什么意义了,乘积一直都是0。因此,0应该是作为两个子数组间的分界元素,那么我们就要使用一个result来保存中间变量的最大值,最后是要作为返回值返回的。此外,在开始下一个子数组的计算时,前面的max和min肯定是要设为下一个子数组的首元素的,那么这里要怎么处理呢?想一想······
其实很简单,我们只要保存这个0,然后留到下一个开始元素,与开始元素进行比较,那么max和min就可以设为我们想要的首元素的值了。因此,我们的比较表达式是:
max = Math.max(nums[i], nums[i]*max 或者 nums[i]*min)
min = Math.min(nums[i], nums[i]*min 或者 nums[i]*max)
解释一下:如果nums[i]是一个非0的数,那么取max或者取min一定是取后面的这个表达式的值;而如果nums[i]是0,那么max和min肯定被置0,在下一步与下一个子数组的首元素进行比较时,就可以将这个首元素赋到max或者min中去。
下面是代码:
public int maxProduct(int[] nums) {
int max = nums[0];
int min = nums[0];
int result = nums[0];
for(int i = 1; i < nums.length; i++) {
int temp = nums[i];
if(temp < 0) {
int tempMin = min;
min = Math.min(temp, temp*max);
max = Math.max(temp, temp*tempMin);
}
if(temp >= 0) {
max = Math.max(temp, temp*max);
min = Math.min(temp, temp*min);
}
result = Math.max(result, max);
}
return result;
}
总的来说,这道题的核心就是动态规划,要想到使用max和min来保存中间值,然后根据max和result的值来更新所需要的最大值;其次就是在遇到正整数、负整数、0三种情况时分别判断,并做出一个总的处理方法,这道题就可以解决了。
谢谢大家观看我的博客。如果有不明白的地方,或者是文中有错误的地方,欢迎指出,谢谢!如果大家喜欢我的博客,也可以给我点点赞。你们的点赞就是我的动力!