zoukankan      html  css  js  c++  java
  • 【算法拾遗】子数组的最大乘积

    版权声明:本文为博主原创文章。未经博主同意不得转载。 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;
    }

查看全文
  • 相关阅读:
    常用dos命令
    最新Java校招面试题及答案
    计算机的基本组成及其工作原理
    java中的三大排序算法
    JSP九大内置对象的作用和用法总结
    java代码实现二叉树的遍历
    转发和重定向的区别
    解决中文乱码问题大全
    创建线程的三种方式对比
    Excel 不同文件、sheet 关联引用(vlookup函数)
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10551529.html
  • Copyright © 2011-2022 走看看