转载请注明出处: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;
}