问题起源于《数据结构与算法分析-C语言描述》一书中的习题2.12。
存在序列A(a1,a2,......,an ),(在此仅讨论序列A中元素均为整数的情况)
问:给出有效的算法求解最大子序列乘积。
一看此题,容易想到的是穷举所有的可能的子序列,求乘积后去最大值,代码如下。
1 int MaxProduct(int a[], int len) 2 { 3 int Max = a[0]; 4 for(int i = 0; i < len; ++i) 5 { 6 int thisMax = 1; 7 for(int j = i; j < len; ++j) 8 { 9 thisMax *= a[j]; 10 Max = Max<thisMax ? thisMax:Max; 11 } 12 } 13 14 return Max; 15 }
此算法的复杂度容易计算得O(n2)。
根据书中对最大子序列和问题的线性算法求解,进一步探索对该问题的线性求解得可能性。
同样的,从问题的最终解的形式出发,假设序列A最大乘积的子序列为(ai,ai+1,....aj)。
由此假设P(k)为以ak结尾的子序列的最大乘积,N(k)为以ak结尾的子序列的最小乘积。
定义递推公式如下:
若 ak > 0; P(k) = ak * P(k-1), N(k) = ak * N(k-1);
ak = 0; P(k) = N(k) = 0;
ak < 0; P(k) = ak * N(k-1), N(k) = ak * P(k-1);
代码实现如下:
1 int MaxProduct(int a[], int len) 2 { 3 int Max = a[0]; 4 int ThisMax = 0, ThisMin = 0; 5 6 for(int i = 0; i < len; ++i) 7 { 8 if(0 == a[i]) 9 { 10 ThisMax = 0; 11 ThisMin = 0; 12 13 } 14 else if(a[i] > 0) 15 { 16 ThisMax = ThisMax ? ThisMax*a[i] : a[i]; 17 ThisMin = ThisMin ? ThisMin*a[i] : ThisMin; 18 } 19 else if(a[i] < 0) 20 { 21 int tmp = ThisMax; 22 ThisMax = ThisMin ? ThisMin*a[i] : 0; 23 ThisMin = tmp ? a[i]*tmp : a[i]; 24 } 25 26 Max = Max>ThisMax?Max:ThisMax; 27 } 28 29 return Max; 30 }
容易计算得到该算法计算复杂度为O(n)。