您的位置:首页 > 其它

少一个数的子序列的最大乘积

2012-08-04 20:38 267 查看
问题描述:

n个数组成的一个序列,求任意(n - 1)个数的组合中乘积最大的一组,规定不能用除法。这个问题来自<编程之美>。

这n个数存于数组A[0..n-1]中。

1 解法一

设s[i]为数组A[]中前i个数的乘积,即

s[i] = 1 i = 0时,

s[i] = s[i - 1] * A[i] i = 1,2,...,n

设t[i]为数组A[]中后 n-i 个数的乘积,即

t[i] = 1 i = n时,

t[i] = t[i + 1] * A[i] i = n-1,n-2,...,0

设p[i]为处A[i]元素外,其余 n-1 个元素的乘积,则

p[i] = s[i] * t[i + 1] i = 0,1,...,n-1

由此可得出下面的算法实现:

int maxProduct(int A[], int n)
{
int s[n + 1], t[n + 1],p
, i, max;

for (s[0] = 1, i = 1;i <= n;i++)     //计算s[i],时间为O(n)
s[i] = s[i -1] * A[i - 1];
for (t
= 1, i = n - 1;i >= 0;i--) //计算t[i],时间为O(n)
t[i] = t[i + 1] * A[i];
for (i = 0;i < n;i++)                //计算p[i],时间为O(n)
p[i] = s[i] * t[i + 1];

for (max = p[0], i = 1;i < n;i++)    //找出最大的乘积,时间O(n)
if (p[i] > max)
max = p[i];
return  max;
}


总的时间复杂度为O(n),算法有很多不足,比如计算了很多此乘法,计算机需要花大量的时间去作乘法操作。

2 解法二

设P为A[]中n个数的乘积,A(n-1)表示n-1个数的组合,P(n-1)表示n-1个数组合的乘积。对P的正负性进行分析:

(1) P = 0。则这n个数中至少有一个数为0,除去这个0,设其余n-1个数的乘积为Q,若:

(a) Q = 0 return 0

(b) Q > 0 return Q

(c) Q < 0 return 0

(2) P < 0。去掉一个负数,这个负数是数组A[]中所有负数之中最大的(绝对值最小的),其余n-1个数的乘积就是所求。

(3) P > 0。则:

(a) 若数组中有正数,则去掉数组中所有正数之中最小的一个,其余n-1个数的乘积即是所求。

(b) 若数组中无正数,去掉数组中最小的负数(绝对值最大的),其余n-1个数的乘积即是所求。

其实不需要求出P的值,而只需要统计数组A[]中正数、负数、零的个数即可分析问题了。

算法如下:

int improvedMaxProduct(int A[], int n)
{
int positive, zero, nagative, i, temp, k;
positive = zero = nagative = 0;

for (i = 0;i < n;i++)
if (A[i] > 0)
positive++;
else if (A[i] == 0)
zero++;
else
nagative++;
//printf("positive = %d, zero = %d, nagative = %d\n", positive, zero, nagative);
if (zero >= 2)                        //数组中有至少两个零,返回-1(代表结果是零)
return -1;
if (zero == 1 && nagative % 2 == 1)   //数组中有一个零,但剩下的n-1个数的乘积是负值,返回-1
return -1;
if (zero == 1 && nagative % 2 == 0) { //数组中有一个零,但剩下的n-1个数的乘积是正值,去掉这个零
for (i = 0;i < n;i++)
if (A[i] == 0)
return i;
}
//之后是数组中没有零的情况
if (nagative % 2 == 1) {              //P < 0
for (i = 0;A[i] > 0;i++)
continue;

for (temp = A[i], k = i, ++i;i < n;i++)
if (A[i] < 0 && A[i] > temp) {
temp = A[i];
k = i;
}
return k;
} //if
//p > 0
if (positive > 0) {            //数组中有正数
for (i = 0;A[i] < 0;i++)
continue;

for (temp = A[i], k = i, ++i;i < n;i++)
if (A[i] > 0 && A[i] < temp) {
temp = A[i];
k = i;
}
return k;
} else {                       //数组中没有正数
for (temp = A[0], k = 0, i = 1;i < n;i++)
if (A[i] < temp) {
temp = A[i];
k = i;
}
return k;
}

}


返回值更改了,当最大乘积是0时,函数返回-1;否则返回去掉的那个数在数组A[]中的下标。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐