[leetcode oj]Maximum Product Subarray

来源:互联网 发布:淘宝上怎么应聘手模 编辑:程序博客网 时间:2024/05/06 02:11

题目: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.

题目解析:题目要求在一个整数数组中找到一个连续的子数组,使得这个子数组中所有元素的成绩最大。

很naive的想法就是两个for循环,依次计算任意两个下标之间的乘积,然后找到最大的。这个算法的时间复杂度为O(n*n),空间复杂度为常数。但是会在数组很长的情况下超时。所以,为了寻找更快的算法,需要对这个问题进行一下分析:

整数包括正整数,负整数和零。一个拥有最大乘积的子数组会满足如下的条件:

(1)子数组起始的前一个元素是0或负数;

(2)子数组结束的后一个元素是0或负数;

(3)两端最多只有一个负数;

因此,要考虑如何得到子问题:显然,0是分界点,子数组中一定不会包含0,除非只有负数和零交替出现。

数组中的0将数组分割成了一些segments。其中,每个segment中都是不为0的整数。这样全局的最大可以等价于这个segments中的最大值中的max。而如果出现所有segments都为负数,那么最大值取0,因为0为边界值。(这就是上面说的特殊情况)

下面就是最复杂的一部分:在代码中给出了如何计算不包含零的序列中最大值的思路。

即,将数组分成三部分:起始到第一个为负的情况,最后一个负值到结束,和中间部分。

当然,这又要分很多种情况考虑,因为并不是每个序列都可以刚刚好被分成三段,有可能只有两段或一段的情况:

(1)只有一个negative element(两段)

(2)没有negative element(一段)

(3)只有两个连着的negative element(两段)

为什么要这么分呢?因为中间那段乘积要么为正,要么为负;如果为正,说明有偶数个负值,直接求全部的乘积;如果为负,需要考虑包含左边还是右边的某一段。两边的两段一定为负。

思路c++代码如下:

class Solution {public:int static maxProduct(int A[], int n) {int begin, end, result, max;begin = 0;vector<int> product;/*first consider the zero seperation pointsif there exist zero point at position i, i.e A[i] == 0divide array into different sectionsfind begin and end of the sectionsThe point is how to find exact the begin and end position ?condition 1: zeros at beginningcondition 2: non-zeros at endingcondition 3: zeros in the middlecondition 4: no zeros*/for (int i = 0; i < n; i++){if (A[i] == 0 || i == n - 1){if (A[i] == 0)end = i - 1; //condition 1 and 3elseend = i; //condition 2 and 4result = subMaxPro(A, n, begin, end);if (result < 0 && A[i] == 0)product.push_back(0);elseproduct.push_back(result);begin = i + 1;}}max = product[0];for (int i = 0; i < product.size(); i++){if (product[i] > max)max = product[i];}return max;}/*subMaxPro()compute the max value of segment A[begin..end] of an array But there are many situations to consider:1 begin > end (the beginning is zero)2 begin == end (return A[begin])3 begin < end (consider different situations)core of the algorithms........find the first negative and last negative elementscompute the products of three part below:first = A[begin...first negative]mid = A[first negative + 1...last negative - 1]last = A[last negative - 1...end]still many situations to consider....no negative elements....(give the initial value -1)only one negative element.....(first negative index == last negative index)more than one negative elements....(first negative index < last negative index)no middle values...first negative index == last negative index - 1has middle values....*/int static subMaxPro(int A[], int n, int begin, int end){int first, mid, last;int idxFirst = -1, idxLast = -1;if (begin > end)return 0;else if (begin == end){return A[begin];}first = 1;for (int i = begin; i <= end; i++){first = first * A[i];if (A[i] < 0){idxFirst = i;break;}}last = 1;for (int i = end; i >= begin; i--){last = last * A[i];if (A[i] < 0){idxLast = i;break;}}mid = 1;//there are negative elementsif (idxFirst != -1 && idxLast != -1){for (int i = idxFirst + 1; i < idxLast; i++){mid = mid * A[i];}}//there is no negative elementelse{for (int i = begin; i <= end; i++){mid = mid * A[i];}}int max;//only one negative valuesif (idxFirst == idxLast && idxFirst != -1){int a, b;a = first / A[idxFirst];b = last / A[idxLast];if (a > b)max = a;elsemax = b;}// no negative valueelse if(idxFirst == -1 && idxLast == - 1){max = mid;}//more than one negative valueselse{if (mid > 0)max = mid * first * last; // bugs...else{int a, b;a = mid * first;b = mid * last;if (a > b)max = a;elsemax = b;}}return max;}};


0 0