您的位置:首页 > 其它

401最大连续乘积子串

2014-07-22 15:56 435 查看

题目:

给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的。

思路1:

暴力法:将所有的可能都罗列出来,时间复杂度为O(n^2)

double maxProductSubString(double *data, int n)
{
	double maxResult = data[0];

	for(int i=0;i<n;i++)
	{
		double x = 1;
		for(int j=i;j<n;j++)
		{
			x *= data[j];
			if(x>maxResult)
			{
				maxResult = x;
			}
		}

	}
	return maxResult;
}
思路二:

利用动态规划的方法:由于在数组中有正数和负数,所以需要记录最大的乘积和最小的乘积,maxend和minend,最小乘积乘以一个负数可能成为最大乘积,利用状态转移方程进行计算:

maxend = max(max(maxend*a[i],minend*a[i]),a[i]);

minend = min (min(maxend*a[i],minend*a[i]),a[i]);

对于元素a[i],在0-i中,要么是与maxend相乘之后变为最大乘积,要么与minend相乘变成最大乘积,或者本身就是最大乘积。

初始化都为a[]

double maxProductsubString_dynamic(double *data, int n)
{
	double maxend, minend;
	maxend = minend = data[0];
	double result = data[0];
	for(int i=1;i<n;i++)
	{
		double end1 = maxend*data[i],end2 = minend*data[i];
		maxend = max(max(end1,end2),data[i]);
		minend = min(min(end1,end2),data[i]);
		result = max(maxend,result);
	}
	return result;
	
}
时间复杂度为O(n)


举一反三

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

分析:我们可以把所有可能的(N-1)个数的组合找出来,分别计算它们的乘积,并比较大小。由于总共有N个(N-1)个数的组合,总的时间复杂度为O(N^2),显然这不是最好的解法。
int maxN_1ProductSubString(int *data, int n)
{
	int maxResult=1;
	for(int k=1;k<n;k++)
		maxResult *= data[k];
	for(int i=0;i<n;i++)
	{
		int produce = 1;
		for(int j=0;j<n;j++)
		{
			if(j != i)
			{
				produce *= data[j];
			}
		}
		if(produce > maxResult)
			maxResult = produce;
	}
	return maxResult;
}
思路二:
一空间换时间,利用两个数组s[],t[],s[i]记录0-i元素的乘积,t[i]代表i-n-1元素的乘积,那么去除a[i]后的乘积是s[i-1]*t[i+1],由于只需要扫描两遍数组,所以时间复杂度是线性的O(n)

int maxN_1ProductSubString2(int *data, int const n)
{
	int *s = new int
;
	int *t = new int
;
	s[0] = data[0];
	t[n-1] = data[n-1];
	for(int i=1;i<n;i++)
	{
		s[i] = s[i-1] * data[i];
	}
	for(int j=n-2;j>=0;j--)
	{
		t[j] = t[j+1] * data[j];
	}
	
	int maxResult =  s[0] * t[2];

	for(int i=1;i<n-1;i++)
	{
		int r = s[i-1] * t[i+1];
		if(r > maxResult)
			maxResult = r;
	}
	return maxResult;
}
在上述的基础上,可以进行逻辑判断,减少计算量:

假设N个整数的乘积为P,针对P的正负性进行如下分析(其中,AN-1表示N-1个数的组合,PN-1表示N-1个数的组合的乘积)。

1.P为0

那么,数组中至少包含有一个0。假设除去一个0之外,其他N-1个数的乘积为Q,根据Q的正负性进行讨论:

Q为0

说明数组中至少有两个0,那么N-1个数的乘积只能为0,返回0;

Q为正数

返回Q,因为如果以0替换此时AN-1中的任一个数,所得到的PN-1为0,必然小于Q;

Q为负数

如果以0替换此时AN-1中的任一个数,所得到的PN-1为0,大于Q,乘积最大值为0。

2. P为负数

根据“负负得正”的乘法性质,自然想到从N个整数中去掉一个负数,使得PN-1为一个正数。而要使这个正数最大,这个被去掉的负数的绝对值必须是数组中最小的。我们只需要扫描一遍数组,把绝对值最小的负数给去掉就可以了。

3. P为正数
类似地,如果数组中存在正数值,那么应该去掉最小的正数值,否则去掉绝对值最大的负数值。

上面的解法采用了直接求N个整数的乘积P,进而判断P的正负性的办法,但是直接求乘积在编译环境下往往会有溢出的危险(这也就是本题要求不使用除法的潜在用意),事实上可做一个小的转变,不需要直接求乘积,而是求出数组中正数(+)、负数(-)和0的个数,从而判断P的正负性,其余部分与以上面的解法相同。

在时间复杂度方面,由于只需要遍历数组一次,在遍历数组的同时就可得到数组中正数(+)、负数(-)和0的个数,以及数组中绝对值最小的正数和负数,时间复杂度为O(N)。
#define MAX_Postive 100
#define MIN_Negative -100

int maxN_1ProductSubString3(int *data, int const n)
{
	int *s = new int
;
	int *t = new int
;
	s[0] = data[0];
	t[n-1] = data[n-1];
	for(int i=1;i<n;i++)
	{
		s[i] = s[i-1] * data[i];
	}
	for(int j=n-2;j>=0;j--)
	{
		t[j] = t[j+1] * data[j];
	}

	int num_zero=0,num_postive=0,num_negative=0;
	int position_min_postive,position_max_negative,position_zero;
	int min_postive = MAX_Postive;
	int max_negative = MIN_Negative;
	for(int k=0;k<n;k++)
	{
		if(data[k]==0)
		{
			++num_zero;
			position_zero = k;
		}
		else if(data[k]>0)
		{
			++num_postive;
			if(data[k]< min_postive)
			{
				position_min_postive = k;
				min_postive = data[k];
			}
		}else
		{
			++num_negative;
			if(data[k]>max_negative)
			{
				position_max_negative = k;
				max_negative = data[k];
			}
		}

	}
	int maxResult;

	if(num_zero != 0)
	{
		if(num_zero == 1)
		{
			if(num_negative % 2 ==0)
			{
				if(position_zero == 0)
					maxResult = t[1];
				else if(position_zero == n-1)
					maxResult = s[n-2];
				else
					maxResult = s[position_zero-1]*t[position_zero+1];
			}else
				maxResult = 0;
		}else
		{
			maxResult = 0;
		}
	}else
	{
		if(num_negative %2 == 0)
		{
			if(position_min_postive == 0)
					maxResult = t[1];
			else if(position_min_postive == n-1)
					maxResult = s[n-2];
			else
					maxResult = s[position_min_postive-1]*t[position_min_postive+1];
		}else
		{
			if(position_max_negative == 0)
					maxResult = t[1];
			else if(position_max_negative == n-1)
					maxResult = s[n-2];
			else
					maxResult = s[position_max_negative-1]*t[position_max_negative+1];
		}
	}
	return maxResult;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: