题目: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 points
if there exist zero point at position i, i.e A[i] == 0
divide array into different sections
find begin and end of the sections
The point is how to find exact the begin and end position ?
condition 1: zeros at beginning
condition 2: non-zeros at ending
condition 3: zeros in the middle
condition 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 3
else
end = i; //condition 2 and 4
result = subMaxPro(A, n, begin, end);
if (result < 0 && A[i] == 0)
product.push_back(0);
else
product.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 elements
compute 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 - 1
has 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 elements
if (idxFirst != -1 && idxLast != -1){
for (int i = idxFirst + 1; i < idxLast; i++){
mid = mid * A[i];
}
}
//there is no negative element
else{
for (int i = begin; i <= end; i++)
{
mid = mid * A[i];
}
}
int max;
//only one negative values
if (idxFirst == idxLast && idxFirst != -1){
int a, b;
a = first / A[idxFirst];
b = last / A[idxLast];
if (a > b)
max = a;
else
max = b;
}
// no negative value
else if(idxFirst == -1 && idxLast == - 1){
max = mid;
}
//more than one negative values
else
{
if (mid > 0)
max = mid * first * last; // bugs...
else{
int a, b;
a = mid * first;
b = mid * last;
if (a > b)
max = a;
else
max = b;
}
}
return max;
}
};