今天跟项目经理聊完天,正好不要再操心项目的事情了,闲来没事就去看了下leetcode,发现又多了一题:https://oj.leetcode.com/problems/maximum-product-subarray/

因为朋友面试的时候正好遇到了这题,这里就当记录一下。


英文题就不贴了,自己去看吧。意思就是求数组的最大子序列积。这个名字是如此的熟悉,最大子序列和是一道很经典的题目,网上可以搜到很多,比如这个人就写的很好,一看就懂:http://blog.csdn.net/sgbfblog/article/details/8032464


换成积了,差别也不大。


O(N^2)解法

先说最朴质的解法,无非是遍历然后计算出所有的积,一一比较找到最大的罢了,跟和的第一种解法对应,于是我写下了这段代码:

int maxProduct(int A[], int n) {
    int max = A[0];
    for (int i = 1; i < n; ++i) {
        int product = 1;
        for (int j = i; j < n; ++j) {
            product *= A[j];
            if (product > max) {
                max = product;
            }
        }
    }
    return max;
}

根据leetcode的尿性,这样的解法肯定是超时的,果不其然,提交就超时。


O(N)解法

我没有去看怎么弄出一个o(nlgn)的解法,受到上面那个博客里第三解法的启发,在求最大子序列和的时候,递推公式是:Max[i] = max(Max[i-1] * A[i], A[i])。

仔细想想,积应该不光是这样,因为存在负负得正的乘法规则,所以 Max[i] 有可能是 i-1 中的负数积乘以 A[i] 得到,表征这样一种可能性,我们需要记录前 i-1 中的最小积,其实如果那个最小的积不是负数又或者就没有必要,所以

if (Min[i-1] < 0 && A[i] < 0)

    Max[i] = max(Max[i-1] * A[i],  Min[i-1] * A[i])

else

    Max[i] = max(Max[i-1] * A[i], A[i])

为了代码的简洁,懒得去判断正负号了,总之:Max[i] = max(Max[i-1] * A[i], Min[i-1] * A[i], A[i])。这样就可以写代码:

int max3(int a, int b, int c)
{
    if ((a >= b) && (a >= c))
        return a;
    return max3(b, c, a);
}
int min3(int a, int b, int c)
{
    if ((a <= b) && (a <= c))
        return a;
    return min3(b, c, a);
}
int maxProduct(int A[], int n) {
    int max = A[0];
    int maxtemp = A[0], mintemp = A[0];
    int temp1 = 0, temp2 = 0;
    for (int i = 1; i < n; ++i) {
        temp1 = maxtemp * A[i];
        temp2 = mintemp * A[i];
        maxtemp = max3(temp1, temp2, A[i]);
        mintemp = min3(temp2, temp1, A[i]);
        if (maxtemp > max)
            max = maxtemp;
    }
    return max;
}


别看代码丑,提交过了哦:)