《编程之美》上有一道关于在长度为n的数组中找到n-1个元素乘积最大的题目,不过这并不是本文要讨论的。
本文讨论的是另一种情况,给定一个长度为n的浮点数组,找一个长度任意的子数组(子数组的元素在原数组中是连续存放的),这个子数组的乘积最大。
通常,找一个满足指定条件子数组都会使用动态规划。递归缩小问题规模的同时,保持问题的数目不会指数增长。不过,本文的这个问题中,情况稍复杂
一些,由于数组元素可能为正,为负,为0,绝对值可能大于1,也可能小于1。要使用动态规划,需要合理设计递归逻辑和保存的临时数据。
定义p(m)从位置m开始,包含第m个元素的最大子数组乘积,那么我们这个问题的解就是: maxp(n) = max { p(i), 0<=i<=n} 。
而p(m)我们希望从p(m+1)计算出来,由于数组中元素可能为正,也可能为负,不妨再定义:q(m)为从位置m开始,包含第m个元素的最小数组乘积(这个乘积必须为非正数)。
那么,
p(m) = p(m+1)*a[m] , p(m+1)>=1且a[m]>0
0, a[m]=0
a[m], p(m+1)<1且a[m]>0
q(m+1)*a[m], a[m]<0
q(m) = q(m+1)*a[m], a[m]>0
0, a[m]=0
a[m], p(m+1)<1且a[m]<0
a[m]*p(m+1) p(m+1)>=1且a[m]<0
p(n)和q(n)作为初始值可以很容易知道。因此整个问题只需要O(n)的时间复杂度以及O(1)的空间复杂度。我写的代码如下,如有错误欢迎指正。
/* author [email protected]
* date June 29, 2013
*/
#include<iostream>
using namespace std;
float lastMaxPN=-1.;
int lastMaxPB=-1;
int lastMaxPE=-1;
float maxPN=-1.;
int maxPB=-1;
int maxPE=-1;
float lastMinNN=1.;
int lastMinNB=-1;
int lastMinNE=-1;
float minNN=1.;
int minNB=-1;
int minNE=-1;
int main() {
int lenNums = 0, i, n, temp, tempIndex;
float *nums;
cin>>lenNums;
nums = new float[lenNums];
for (i=0; i<lenNums; i++) {
cin>>nums[i];
}
n = lenNums - 1;
if (nums[n] >= 0) { // should be carefull about the situation when nums[n]=0.
lastMaxPN = maxPN = nums[n];
lastMaxPB = maxPB = lastMaxPE = maxPE = n;
} else {
lastMinNN = minNN = nums[n];
lastMinNB = minNB = lastMinNE = minNE = n;
}
n --;
while (n>=0) {
if (nums[n] > 0) {
//update lastMaxPN if possible:
if (lastMaxPN <= 0) {
lastMaxPN = nums[n];
lastMaxPB = lastMaxPE = n;
} else {
if (lastMaxPN >= 1) {
lastMaxPN *= nums[n];
lastMaxPB = n;
} else if (nums[n]>lastMaxPN) {
lastMaxPN = nums[n];
lastMaxPB = lastMaxPE = n;
}
}
//update lastMinNN if possible:
if (lastMinNN <= 0) {
lastMinNN *= nums[n];
lastMinNB = n;
}
} else if (nums[n] == 0) {
lastMaxPN = lastMinNN = 0;
lastMaxPB = lastMaxPE = lastMinNB = lastMinNE = n;
} else {
temp = lastMinNN;
tempIndex = lastMinNE;
if (lastMaxPN*nums[n] <= temp) {
lastMinNN = lastMaxPN*nums[n];
lastMinNB = n;
lastMinNE = lastMaxPE;
}
if (lastMinNN > nums[n]) {
lastMinNN = nums[n];
lastMinNB = lastMinNE = n;
}
if (temp <=0) {
if (temp*nums[n] > lastMaxPN) {
lastMaxPN = temp*nums[n];
lastMaxPB = n;
lastMaxPE = tempIndex;
}
}
}
//update max positive number and min negative number:
if (lastMaxPN > maxPN && (lastMaxPE-lastMaxPB)>(maxPE-maxPB)) {
maxPN = lastMaxPN;
maxPB = lastMaxPB;
maxPE = lastMaxPE;
}
if (lastMinNN < minNN && (lastMinNE-lastMinNB)>(minNE-minNB)) {
minNN = lastMinNN;
minNB = lastMinNB;
minNE = lastMinNE;
}
n --;
}
cout<<maxPN<<"("<<maxPB<<":"<<maxPE<<")"<<endl;
}