《算法分析与设计》Week 2
152. Maximum PRoduct Subarray
Description:
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
.
Solution:
一、题意理解
给定一个int型的数组,找到乘积最大的子序列,返回这个乘积。
二、分析
1、很明显是动态规划题。
2、因为数组中的数有正有负,可能本来某个序列乘积是负的,很小,但是如果下一个数是负数,负负得正,就会立即使乘积变 的很大,所以我们不仅要维护一个局部最大值,也要维护一个局部最小值,当然还有一个全局最大值。
3、列出如下的动态规划方程。
(1)设curmax为局部最大值,curmin为局部最小值,max为全局最大值,初始值均为curmax = curmin = max = A[0];
(2)for i = 1 to n-1:
// 先保存一下局部最大值
temp = curmax;
// 将“curmax * A[i]”、“A[i]”、“curmin * A[i]” 三者比较,取最大值赋值给curmax
curmax = MAX( MAX(curmax * A[i], A[i]), curmin*A[i]);
// 将“curmin * A[i]”、“A[i]”、“temp * A[i]” 三者比较,取最小值赋值给curmin
curmin = MIN( MIN(curmin * A[i], A[i]), temp * A[i]);
// 保存全局最大值
max = MAX(max, curmax);
(3)遍历完成后,max即是最大乘积。
4、代码如下:
#define MAX(x,y) (x>y? x:y) #define MIN(x,y) (x<y? x:y) class Solution { public: int maxProduct(int A[], int n) { if(n==1) return A[0]; int curmax = A[0]; int curmin = A[0]; int max = A[0]; int temp; for(int i=1;i<n;i++) { temp = curmax; curmax = MAX( MAX(curmax*A[i],A[i]), curmin*A[i] ); curmin = MIN( MIN(curmin*A[i],A[i]), temp*A[i]); max = MAX(max, curmax); } return max; } }; 三、结果及优化1、Runtime: 16ms
2、看到Solutions中有3ms的解法,去瞻仰一番,意思是可以证明出:
(1) 假设在A[]中没有0存在,那么结果必是A[0] A[1] .... A[i] 或 A[j] *A[j+1] A[n - 1]。
(2) 如果A[]中有0存在(假设A[k] == 0),那么可以将数组拆分为A[0],A[1]...A[k - 1 ] 和 A[k + 1] A[k + 2]...A[n-1] 两个数组,然后再应用(1)即可。
3、怎么证明的我也不知道,大致想了一下,可以分奇数个负数和偶数个负数来讨论。贴上大神的代码:
class Solution { public: int maxProduct(int A[], int n) { int frontProduct = 1; int backProduct = 1; int ans = INT_MIN; for (int i = 0; i < n; ++i) { frontProduct *= A[i]; backProduct *= A[n - i - 1]; ans = max(ans,max(frontProduct,backProduct)); frontProduct = frontProduct == 0 ? 1 : frontProduct; backProduct = backProduct == 0 ? 1 : backProduct; } return ans; } };