[编程之美] PSet2.13 子数组的最大乘积

问题:

给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合中乘积最大的一组。


方法一:暴力枚举

       把所有可能的N-1个数的组合求出来,分别计算他们的乘积。对于N个数而言,每一个数都需要计算N-1个数的成绩,于是复杂度为N(N-1)即O(N^2)的复杂度,显然不是最好的解法。

// 暴力枚举,需要访问N(N-1)个数
//返回那个没有被用到的数以及最大乘积
pair<int,int> findMaxMul(int Arr[] , int arrLen)
{
	int maxMulSum = 0;
	int index;//保存未用到的数的下标
	for(int i=0 ; i<arrLen ; i++){//选择一个数剔除,计算其余的数的乘积
		int mulSum = 1;
		for(int j=0 ; j<arrLen ; j++){
			if(j == i)
				j++;
			mulSum *=Arr[j];
		}
		if(mulSum > maxMulSum){
			maxMulSum = mulSum;
			index = i;
		}
	}
	return make_pair(Arr[index] , maxMulSum);
}

int main()
{
	int Arr[9] = {42,-5,6,-8,1,9,-5,33,12};
	pair<int,int> p = findMaxMul(Arr , 9);
	cout<<p.first<<" "<<p.second<<endl;
	return 0;
}
方法二:空间换时间策略

       用两个数组分别记录某个被剔除数据Arr[i]前后连乘积,S[i]数组表示数组前i个元素的连乘积,边界条件S[0]=1,可以知道S[1]=Arr[0],S[2]=Arr[0]*Arr[1]······,T[i]数组表示后(N-i)个元素的连乘积,边界条件T[N]=1,可以知道T[N-1]=Arr[N],T[N-2]=Arr[N]*Arr[N-1]······

      于是可以得到对于剔除Arr[i]后的连乘积,可以这样求mulSum[i] = S[i-1]*T[i+2];下面是代码:

//用空间换时间的方法,设定前缀连乘积数组S[i]和后缀连乘积数组T[i]
//结果mulSum[i] = S[i]*T[i+2];  i的范围在[0,arrLen-1];
pair<int,int> findMaxMul(int Arr[] , int arrLen)
{
	int *S = new int[arrLen+1];
	int *T = new int[arrLen+1];
	int *sumMul = new int[arrLen];
	int maxMul = 0;
	int index = -1;
	//初始化数组S、T
	S[0]=1;
	T[arrLen]=1;
	for(int i=1 ; i<arrLen+1 ; i++)
		S[i] = S[i-1]*Arr[i-1];
	for(int i=arrLen-1 ; i>=0 ; i--)
		T[i] = T[i+1]*Arr[i];

	for(int j=0 ; j<arrLen ; j++){
		sumMul[j] = S[j]*T[j+1];
		if(maxMul < sumMul[j]){
			maxMul = sumMul[j];
			index = j;
		}
	}
	delete []S;
	delete []T;
	delete []sumMul;
	return make_pair(Arr[index] , maxMul);
}
方法三:启发式方法(根据经验得出计算方法)

       对N个数的乘积进行分析,用启发式的方式得到在满足乘积最大情况下要删去那个数。
          1.数组中有多于一个零则最大乘积为0;
       2.数组中只有一个零,而有奇数个负数,则最大乘积必定为0;
       3.数组中只有一个零,而有偶数个负数,则最大乘积为除去0的元素的乘积; 
       4.数组中没有零,而有奇数个负数,则最大乘积为除去绝对值最小的负数的乘积;
       5.数组中没有零,而有偶数个负数,则最大乘积为除去最小的正数的乘积。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值