《算法分析与设计》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;
    }
};