Leetcode(152) Maximum Product Subarray

来源:互联网 发布:java 获取方法的泛型 编辑:程序博客网 时间:2024/04/30 11:44

题目如下:

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都没有,那么就把所有的输入全部相乘得到一个结果,如果这个结果为>0,必然是largest product,如果结果<0,那么就从输入数组的左边开始向右扫描,直到找到第1个负数为主,那么此时去掉左边的subarray(从输入数组的第1个开始,到第1个负数为止的子数组。例如,[-2, 2, 3, -3]的左subarray为[-2], [2, -2, 3, -3]的左subarray为[2, -2])后,去掉左边的subarray后剩下数的乘积必然为正数。同样的过程按照从右到左的顺序对右边的数组走一遍,得到去掉右边subarray后剩下数的乘积,也必然为正数。比较两个正数,较大者为所求。把上面的过程放入辅助函数subsetMax中。

如果输入数组中有0,就把0作为分界线,得出一些子数组,对每个子数组做上面的事情。在每个子数组得到的最大乘积中选择最大的。

比较特殊的情况是 当输入数组为[-1],此时需要在subsetMax中特殊处理一下。

这道题目也是个非常具有面试题目感觉的题目,没有任何算法纯代码,但是代码很有区分度。
代码如下:

class Solution {    private:    int subsetMax(int sub[], int n) {        if (n == 1) return sub[0];        int subsetProduct = 1;        int posStart = -1;        int posEnd = -1;        for (int i = 0; i < n ; ++i)            subsetProduct *= sub[i];        if (subsetProduct > 0) return subsetProduct;        int leftSubsetProduct = 1;        int rightSubsetProduct = 1;        for (posStart = 0; posStart < n ; ++posStart)            if (sub[posStart] < 0) break;        for (int i = posStart + 1; i < n; ++i)            leftSubsetProduct *= sub[i];        for (posEnd= n-1; posEnd >= 0 ; --posEnd)            if (sub[posEnd] < 0) break;        for (int i = posEnd - 1; i >= 0; --i)            rightSubsetProduct *= sub[i];        return leftSubsetProduct > rightSubsetProduct ? leftSubsetProduct:rightSubsetProduct;    }    public:        int maxProduct(int A[], int n) {        int arrayMax = INT_MIN;        int subStart = 0;        int subEnd = 0;        int curMax = INT_MIN;        bool hasZero = false;        while (subStart < n) { // 简化了while (subStart < n && subEnd < n) 因为while{}内部的最后一步是subStart = subEnd + 1;            while (subStart < n && A[subStart]==0) {                hasZero = true;                subStart++;            }            subEnd = subStart;            while (subEnd < n && A[subEnd]!=0)                subEnd++;            if (subEnd < n)                hasZero = true;            if (subStart < subEnd) {                curMax = subsetMax(A + subStart, subEnd - subStart);                if (curMax > arrayMax) arrayMax = curMax;            }            subStart = subEnd + 1;        }        if (hasZero && arrayMax < 0) return 0;        else return arrayMax;    }};

update 2014-11-23

更简洁的思路是动态规划。解答思路来自官网的答案解析。

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] )


There we have a dynamic programming formula. Using two arrays of size n, we could deduce the final answer as f(n-1).

class Solution {public:    int maxProduct(int A[], int n) {        if (n == 0) return 0;        if (n == 1) return A[0];        int result = A[0]; //NOTE: 不能初始化为resutl = INT_MIN,因为已经用了A[0]作为基准了。        int min_product = A[0];        int max_product = A[0];        for (int i = 1; i < n; ++i) {            int org_min = min_product; //NOTE: data dependency: 原始的min max值需要保留下来。            int org_max = max_product; //NOTE: data dependency: 原始的min max值需要保留下来。            max_product = ((org_max * A[i]) > (org_min * A[i]))?(org_max * A[i]):(org_min * A[i]);            max_product = (max_product > A[i]) ? max_product:A[i];            min_product = ((org_max * A[i]) < (org_min * A[i]))?(org_max * A[i]):(org_min * A[i]);            min_product = (min_product < A[i]) ? min_product:A[i];            if (max_product > result)                result = max_product;            //std::cout<<"i = "<<i<<", max="<<max_product<<", min="<< min_product<<" ,res="<<result<<std::endl;        }        return result;    }};



0 0
原创粉丝点击