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
.
即求连续的子数组乘积最大的值,该问题同求解连续子数组和最大的值具有相似性,都可以通过动态规划求解。
连续子数组和最大分析
对于a[i],当前最大值分为三种情况:
case 1:即a[i]即构成子数组和最大;
case 2:a[i]同sum[i-1]构成连续的子数组且和最大,即为sum[i-1]+a[i];
case 3:a[i]不构成连续的子数组,即sum[i-1]为a[0,……i]中连续子数组的最大和
因此,根据上述三种情况,不难知道其状态方程为:sum[i] = max(sum[i-1],a[i],a[i]+sum[i-1])
/**
* 求解a[0],……,a[n-1]连续子数组和且最大
* @param datas
* @return
*/
public int findNegativeMaxSubArraySum(int[] datas) {
<span style="white-space:pre"> </span>int sum = array[0];
<span style="white-space:pre"> </span>for(int i = 1; i < array.length; i++){
<span style="white-space:pre"> </span>sum = max(max(array[i],array[i]+sum),sum);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return sum;
}
对于乘积,情况就有点点不相同,其状态方程并不是product[i] = max(product[i-1],a[i],a[i]*product[i-1])。
对于[-2,-3,-4],其连续的最大乘积为12,但是若按照刚刚提到了状态方程,其结果为6。之所以会这样,是因为那个状态方程没有考虑到负负得正的情况。因此,不仅要维护当前的最大值,还要维护一个最小值。
tmp = start;
start= max(max(start * A[i], A[i]), min_local * A[i]);
min_local = min(min(tmp * A[i], A[i]),min_local*A[i]);
product = max(start, product);
LeetCode的证明:
Let us denote that:
f(k) = Largest product subarray, from index 0 up to k.
Similarly,
g(k) = Smallest product subarray, from index 0 up to k.
Then,
f(k) = max( f(k-1) * A[k], A[k], g(k-1) * A[k] ) g(k) = min( g(k-1) * A[k], A[k], f(k-1) * A[k] )
public int solution(int[] A) {
int start = A[A.length - 1];
int product = A[A.length - 1];
int min_local = A[A.length - 1];
for (int i = A.length - 2; i >= 0; i--) {
int tmp = start;
start = max(max(start * A[i], A[i]), min_local * A[i]);
min_local = min(min(tmp * A[i], A[i]),min_local*A[i]);
product = max(start, product);
}
return product;
}