问题来源:《编程之美》2.13 子数组的最大乘积
给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合乘积中最大的一组,并写出算法的时间复杂度。
1. 把所有(N-1)个数的组合找出来,分别计算它们的乘积,并比较大小,由于总共有N个(N-1)个数的组合,总的时间复杂度是O(N^2),不好。
2. 以空间换时间,计算(N-1)个元素的最大乘积,假定第 i 个元素排除在外,(0<= i <= N-1),那么
p[i] = s[i-1] * t[i+1],
p[i] 表示出去第 i 个元素后的乘积,s[i-1]表示第i个元素前面所有元素的乘积,t[i+1]表示第i个元素后面所有元素的乘积,这样,我们需要从前往后遍历一次数组得到数组s[], 从后往前遍历一次数组得到数组t[], 于是在一个线性时间内就可得到p[], 遍历一次p[]数组就可得到子数组的最大乘积,时间复杂度为O(n).
3. 统计方法,及数组中所有元素的乘积是P,
若P == 0,
则数组中至少包含一个0元素,出去该0元素后所有元素的乘积记为Q,
a,若Q == 0,则数组中包含2个或者2个以上的0元素,无论我们怎么从数组中去(N-1)个元素,子数组的乘积总是0,故子数组的最大乘积是0;
b,若Q > 0,则除去该0元素后的子数组就是子数组的最大乘积;
c,若Q < 0,则表明有奇数个负数,次数无论将0元素来替换数组中的其它任意一个元素得到的乘积总是0,大于Q,故此时子数组的最大乘积是0,子数组中必须包含该0元素;
若P > 0,
a,若数组中存在正元素,则去掉最小的正元素即可;
b,若数组中不存在正元素,则去掉绝对值最大的负元素即可;
若P < 0,
则表明数组中存在奇数个负元素,根据负负得正,去掉绝对值最小的负数即可得到子数组的乘积最大的组合。
程序描述如下:
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
void analyse(int array[], int size)
{
int zeroNum = 0;
int negativeNum = 0;
int positiveNum = 0;
int maxNegative = INT_MIN;
int minPositive = INT_MAX;
int zeroIndex = 0;
int minNegative = 0;
for(int i = 0; i < size; ++i) {
if(array[i] == 0) {
++zeroNum;
zeroIndex = i;
}
else if(array[i] < 0) {
++negativeNum;
if(array[i] > maxNegative)
maxNegative = array[i];
if(array[i] < minNegative)
minNegative = array[i];
}
else {
++positiveNum;
if(array[i] < minPositive)
minPositive = array[i];
}
}
//如果数组中包含两个或者两个以上0,那么子数组的乘积肯定为0
if(zeroNum >= 2) {
printf("all subArray elements' product is equal to zero");
return;
}
//如果数组中只包含一个0,那么分两个情况:
//1.去除该0元素其余所有数的乘积为正,那么去除该0元素后所得的子数组乘积最大
//2.去除该0元素其余所有数的乘积为负,那么子数组最大的乘积为0,子数组中必须包含0元素
if(zeroNum == 1) {
if(negativeNum % 2 == 0) {
printf("the sunArray elements' indexs is except: %d\n", zeroIndex);
}
else {
printf("the subArray must have the index %d of element\n", zeroIndex);
}
return;
}
//如果数组中有偶数个负数:
//1.假定数组中存在正元素,则去掉最小正元素即可得到子数组的最大乘积
//2.假定数组中不存在正元素,则需要去掉最小的负数,即绝对值最大的负数
//如果数组中有奇数个负数:
//则只需要去掉值最大的负数,及绝对值最小的负数
if(negativeNum % 2 == 0 && positiveNum > 0) { //需考虑没有正元素的情况
printf("the subArray elements' indexs in except: %d\n", minPositive);
}
else if(negativeNum % 2 == 0 && positiveNum == 0) {
printf("the subArray elements' indexs is except: %d\n", minNegative);
}
else {
printf("the subArray elements' indexs is except: %d\n", maxNegative);
}
}
int main()
{
int a[] = {-3, -9, -12, -35, -89, 0};
analyse(a, sizeof(a)/ sizeof(int));
}