【算法拾遗】子数组的最大乘积

版权声明:本文为博主原创文章。未经博主同意不得转载。 https://blog.csdn.net/mmc_maodun/article/details/29224185

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

【推广】 免费学中医,健康全家人
原文地址:https://www.cnblogs.com/ldxsuanfa/p/10551529.html