轉載請註明出處:http://blog.csdn.net/ns_code/article/details/29224185
給定一個長度爲N的整數數組,只允許使用乘法,不能使用除法,計算任意N-1個數的組合乘積的最大值。
這道題目重點要注意數組中有負數、0的情況。最直觀的做法就是把所有可能的N-1個數的組合找出來,分別計算他們的乘積,並比較大小。找出所有組合需要O(N)時間,計算每個組合的乘積需要O(N)時間,因此該算法的時間複雜度爲O(N*N)。
編程之美上給出了兩種O(N)的解法。
第一種比較直觀,假設去掉第i個元素後的剩下的N-1個元素的成績爲p[i],則從左向右掃描數組,計算第0到第i-1個元素的乘積s[i],再從右向左掃描數組,計算從第N-1個元素到第i+1個元素的乘積t[i],二者相乘便是除去第i個元素的剩下N-1個元素的乘積p[i],而後比較所有的p[i]即可。由於每次計算s[i+1]和t[i-1]時直接可以利用s[i]和t[i]的結果,因此掃描一次過去的時間複雜度爲O(N),找出p[i]的最大值也是O(N),因此時間複雜度爲O(N)。
第二種方法,將問題轉化到對去掉的那個元素的分析上,只在最後計算一次乘積即可。這種方法要先掃描一次數組,得到數組中正整數的個數、負整數的個數、0的個數,最小的正整數、絕對值最大的負整數和絕對值最小的負整數。而後詳細地根據數組中正負數以及0的個數來判斷要剔除的元素。
1、如果數組中0的個數大於1,則任意N-1個元素的乘積都爲0,去掉任一元素均可;
2、如果數組中0的個數爲1,則需要分兩種情況;
{
1、如果數組中負數的個數爲偶數個,此時去掉0,剩下的N-1個數的乘積最大,爲正值;
2、如果數組中負數的個數爲奇數個,此時N-1個數的乘積最大值爲0,去掉任意一個非0元素即可。
}
3、如果數組中沒有0,則需要分兩種情況:
{
1、如果數組中的負數個數爲奇數個,此時去掉一個負數後的剩下N-1個數的乘積爲正值,要保證這個正值最大,我們需要去掉絕對值最小的負 數,即最大的負數;
2、如果數組中的負數個數爲偶數個,則需要分兩種情況:
{
1、如果數組中沒有正整數,則去掉一個負數後,剩下的N-1個數的乘積爲負值,要保證這個負值最大,我們需要去掉絕對值大的負數 , 即最小的負數;
2、如果數組中有正整數,則去掉最小的正整數,剩下的N-1個元素的乘積即爲最大的。
}
}
按照這種思路實現的代碼如下:
bool flag;
long long MaxProduct(int *arr,int len)
{
if(arr==NULL || len<1)
{
flag = false;
return 0;
}
int minus = 0; //負數個數
int plus = 0; //正數個數
int zero = 0; //0的個數
int minAbsMinus = (signed int)0x80000000; //絕對值最小的負整數,先初始化爲最小的int負數
int maxAbsMinus = -1; //絕對值最大的負整數,先初始化爲最大的負整數
int minPlus = 0x7FFFFFFF; //最小的正整數,先初始化爲最大的int正數
int i;
for(i=0;i<len;i++)
{
if(arr[i] == 0)
zero++;
else if(arr[i] < 0)
minus++;
else
plus++;
if(arr[i]<0 && arr[i]>minAbsMinus)
minAbsMinus = arr[i];
if(arr[i]<0 && arr[i]<maxAbsMinus)
maxAbsMinus = arr[i];
if(arr[i]>0 && arr[i]<minPlus)
minPlus = arr[i];
}
int outNum; //不參與乘積的數
long long result = 1; //n-1個數的最大乘積
//0的個數大於1的情況,這時任意n-1個數的乘積都爲0,
if(zero > 1)
return 0;
//如果有一個0,則需要根據正負數的個數來決定
if(zero == 1)
{
//如果負數的個數爲偶數個,
//則去掉0後的n-1個數的乘積爲正,即爲最大值
if((minus&1) == 0)
outNum = 0;
//如果負數的個數爲奇數個,
//則去掉0後的n-1個數的乘積爲負,因此最大值應該爲0,
//去掉任一個非0元素即可
else
return 0;
}
//如果沒有0,則需要根據正負數的個數來決定
else
{
//如果負數個數爲奇數個,則去掉一個負數後,剩下的n-1個元素的乘積爲正,
//此時去掉絕對值最小的負數,剩下的n-1個數的乘積便最大
if((minus&1) != 0)
outNum = minAbsMinus;
//如果負數個數爲偶數個,這時候要分兩種情況,
//數組中有正數和沒正數
else
{
//如果數組中沒有正數,則n-1個負數的乘積肯定爲負數,
//去掉絕對值最大的負數,便可得n-1個負數乘積的最大值
if(plus == 0)
outNum = maxAbsMinus;
//如果數組中有正數,則去掉最小的正數,便可得n-1個數乘積最大值
else
outNum = minPlus;
}
}
//計算乘積
for(i=0;i<len;i++)
{
if(arr[i] != outNum)
result *= arr[i];
}
return result;
}