《编程之美》 2.13
问题:给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算(N-1)个数的组合乘积中最大的一组,并写出算法的时间复杂度。
解法一:把所有N-1个数的组合找出来,分别计算乘积,比较大小。O(N^2)。
int MaxSubProducti(int a[],int n)
{
assert(n > 1);
int i,j,k,prod,ret;
for (i = 0; i < n; i++){
prod = 1;
for(j = 0; j < i; j++){
prod *= a[j];
}
for(j = i + 1; j < n; j++){
prod *= a[j];
}
if (i == 0) ret = prod;
if (prod > ret) ret = prod;
}
return ret;
}
int MaxSubProductii(int a[],int n)
{
assert(n > 1);
int i,j,prod,ret;
for(i = 0; i < n; i++){
prod = 1;
for(j = 0; j < n; j++){
prod *= (i == j) ? 1 : a[j];
if (prod == 0)// terminate early
break;
}
if (i == 0) ret = prod;
if (prod > ret) ret = prod;
}
return ret;
}
解法二:利用两个数组s和s分别表示从数组a的两端开始计算的乘积,s[i] = a[0]*a[1]*...*a[i-1],t[j] = a[j]*...*a[n-1]。那么p[i] = s[i-1] * t[i+1]。时间复杂度为O(N)。
int MaxSubProductiii(int a[],int n)
{
assert(n > 1);
int *s = (int *)malloc(n*sizeof(int));
int *t = (int *)malloc(n*sizeof(int));
int i,j,lowprod,highprod,maxprod,prod;
lowprod = 1;
highprod = 1;
assert(s != NULL && t != NULL);
for(i = 0; i < n; i++){
j = n - i - 1;
lowprod *= a[i];
highprod *= a[j];
s[i] = lowprod;
t[j] = highprod;
}
maxprod = (s[n-2] > t[1]) ? s[n-2] : t[1];
for(i = 1; i < n - 1; i ++){
prod = s[i-1] * t[i+1];
if (prod > maxprod) maxprod = prod;
}
free(s);
free(t);
return maxprod;
}
解法三:统计数组中正数、负数和零的个数,记录最小的正数、负数以及最大的负数。
1,如果零的个数n_zero大于1,那么最大乘积为0;
2,如果零的个数n_zero为1:
(1),如果负数的个数n_neg为奇数,那么最大乘积为0;
(2),如果负数的个数n_neg为偶数,那么最大乘积计算式扣除a[zeroi];
3,如果零的个数n_zero为0:
(1),如果负数的个数n_neg为奇数,那么最大乘积计算式扣除a[maxnegi];
(2),如果负数的个数n_neg为偶数:
1> 如果正数的个数n_pos为零,那么最大乘积计算式扣除a[minnegi];
2> 如果正数的个数n_pos大于零,那么最大乘积计算式扣除a[minposi];
int MaxSubProductiv(int *a, int n)
{
int n_zero = 0; // count of zero
int n_neg = 0; // count of negative integer
int n_pos = 0;
int maxneg = 0; // maximum negative integer
int minpos = 0; // minimum positive integer
int maxnegi = 0; // index of maxneg
int minposi = 0; // index of minimum positive integer
int zeroi = 0; // index of zero
int minneg = 0;
int minnegi = 0;
int out = -1; // index of the val to be omitted
// when calculating result product
int max = 1;
/* collect some statistic info in one loop */
for(int i = 0; i < n; i++)
{
if(a[i] < 0) //a[i] is negative
{
n_neg++;
if(maxneg == 0)
{
maxneg = a[i];
maxnegi = i;
}
else if(maxneg < a[i])
{
maxneg = a[i];
maxnegi = i;
}
if (minneg == 0) {
minneg = a[i];
minnegi = i;
}
else if (minneg > a[i]) {
minneg = a[i];
minnegi = i;
}
}
else if(a[i] == 0) // a[i] is zero
{
zeroi = i;
if(++n_zero > 1) return 0;
}
else // a[i] is positive
{
n_pos++;
if(minpos == 0)
{
minpos = a[i];
minposi = i;
}
else if(minpos > a[i])
{
minpos = a[i];
minposi = i;
}
}
}
if((n_zero == 1) && (n_neg & 0x1))
{
// one zero and odd negatives
return 0;
}
else if((n_zero == 1) && !(n_neg & 0x1))
{
// one zero and even negatives
printf("one zero and even negatives\n");
out = zeroi;
}
else if((n_zero == 0) && (n_neg & 0x1))
{
// no zero and odd negatives
printf("no zero and odd negatives\n");
out = maxnegi;
}
else if((n_zero == 0) && !(n_neg & 0x1))
{
// no zero and even negatives
printf("no zero and even negatives\n");
if (n_pos == 0){
out = minnegi;
}
else {
out = minposi;
}
}
for(int i = 0; i < n; i++)
{
max *= (i == out) ? 1 : a[i];
}
return max;
}
int MaxSubProductv(int *a, int n)
{
int n_zero = 0; // count of zero
int n_neg = 0; // count of negative integer
int n_pos = 0; // count of positive integer
int maxneg = 0; // maximum negative integer
int minpos = 0; // minimum positive integer
int maxnegi = 0; // index of maxneg
int minposi = 0; // index of minimum positive integer
int zeroi = 0; // index of zero
int minneg = 0;
int minnegi = 0;
int out = -1; // index of the val to be omitted
// when calculating product
int max = 1;
for(int i = 0; i < n; i++)
{
if(a[i] < 0) //a[i] is negative
{
n_neg++;
if(maxneg == 0)
{
maxneg = a[i];
maxnegi = i;
}
else if(maxneg < a[i])
{
maxneg = a[i];
maxnegi = i;
}
if (minneg == 0){
minneg = a[i];
minnegi = i;
}
else {
if (minneg > a[i]){
minneg = a[i];
minnegi = i;
}
}
}
else if(a[i] == 0) // a[i] is zero
{
zeroi = i;
if(++n_zero > 1) return 0;
}
else // a[i] is positive
{
n_pos++;
if(minpos == 0)
{
minpos = a[i];
minposi = i;
}
else if(minpos > a[i])
{
minpos = a[i];
minposi = i;
}
}
}
if (n_zero){
printf("zeros.\n");
if (n_neg & 1)
return 0;
else
out = zeroi;
}
else {
printf("no zero.\n");
if (n_neg & 1)
out = maxnegi;
else if (n_pos == 0){
out = minnegi;
}
else {
out = minposi;
}
}
for(int i = 0; i < n; i++)
{
max *= (i == out) ? 1 : a[i];
}
return max;
}
测试程序:
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <stdlib.h>
int MaxSubProducti(int a[],int n)
{
assert(n > 1);
int i,j,k,prod,ret;
for (i = 0; i < n; i++){
prod = 1;
for(j = 0; j < i; j++){
prod *= a[j];
}
for(j = i + 1; j < n; j++){
prod *= a[j];
}
if (i == 0) ret = prod;
if (prod > ret) ret = prod;
}
return ret;
}
int MaxSubProductii(int a[],int n)
{
assert(n > 1);
int i,j,prod,ret;
for(i = 0; i < n; i++){
prod = 1;
for(j = 0; j < n; j++){
prod *= (i == j) ? 1 : a[j];
if (prod == 0)// terminate early
break;
}
if (i == 0) ret = prod;
if (prod > ret) ret = prod;
}
return ret;
}
int MaxSubProductiii(int a[],int n)
{
assert(n > 1);
int *s = (int *)malloc(n*sizeof(int));
int *t = (int *)malloc(n*sizeof(int));
int i,j,lowprod,highprod,maxprod,prod;
lowprod = 1;
highprod = 1;
assert(s != NULL && t != NULL);
for(i = 0; i < n; i++){
j = n - i - 1;
lowprod *= a[i];
highprod *= a[j];
s[i] = lowprod;
t[j] = highprod;
}
maxprod = (s[n-2] > t[1]) ? s[n-2] : t[1];
for(i = 1; i < n - 1; i ++){
prod = s[i-1] * t[i+1];
if (prod > maxprod) maxprod = prod;
}
free(s);
free(t);
return maxprod;
}
int MaxSubProductiv(int *a, int n)
{
int n_zero = 0; // count of zero
int n_neg = 0; // count of negative integer
int n_pos = 0;
int maxneg = 0; // maximum negative integer
int minpos = 0; // minimum positive integer
int maxnegi = 0; // index of maxneg
int minposi = 0; // index of minimum positive integer
int zeroi = 0; // index of zero
int minneg = 0;
int minnegi = 0;
int out = -1; // index of the val to be omitted
// when calculating result product
int max = 1;
/* collect some statistic info in one loop */
for(int i = 0; i < n; i++)
{
if(a[i] < 0) //a[i] is negative
{
n_neg++;
if(maxneg == 0)
{
maxneg = a[i];
maxnegi = i;
}
else if(maxneg < a[i])
{
maxneg = a[i];
maxnegi = i;
}
if (minneg == 0) {
minneg = a[i];
minnegi = i;
}
else if (minneg > a[i]) {
minneg = a[i];
minnegi = i;
}
}
else if(a[i] == 0) // a[i] is zero
{
zeroi = i;
if(++n_zero > 1) return 0;
}
else // a[i] is positive
{
n_pos++;
if(minpos == 0)
{
minpos = a[i];
minposi = i;
}
else if(minpos > a[i])
{
minpos = a[i];
minposi = i;
}
}
}
if((n_zero == 1) && (n_neg & 0x1))
{
// one zero and odd negatives
return 0;
}
else if((n_zero == 1) && !(n_neg & 0x1))
{
// one zero and even negatives
printf("one zero and even negatives\n");
out = zeroi;
}
else if((n_zero == 0) && (n_neg & 0x1))
{
// no zero and odd negatives
printf("no zero and odd negatives\n");
out = maxnegi;
}
else if((n_zero == 0) && !(n_neg & 0x1))
{
// no zero and even negatives
printf("no zero and even negatives\n");
if (n_pos == 0){
out = minnegi;
}
else {
out = minposi;
}
}
for(int i = 0; i < n; i++)
{
max *= (i == out) ? 1 : a[i];
}
return max;
}
int MaxSubProductv(int *a, int n)
{
int n_zero = 0; // count of zero
int n_neg = 0; // count of negative integer
int n_pos = 0; // count of positive integer
int maxneg = 0; // maximum negative integer
int minpos = 0; // minimum positive integer
int maxnegi = 0; // index of maxneg
int minposi = 0; // index of minimum positive integer
int zeroi = 0; // index of zero
int minneg = 0;
int minnegi = 0;
int out = -1; // index of the val to be omitted
// when calculating product
int max = 1;
for(int i = 0; i < n; i++)
{
if(a[i] < 0) //a[i] is negative
{
n_neg++;
if(maxneg == 0)
{
maxneg = a[i];
maxnegi = i;
}
else if(maxneg < a[i])
{
maxneg = a[i];
maxnegi = i;
}
if (minneg == 0){
minneg = a[i];
minnegi = i;
}
else {
if (minneg > a[i]){
minneg = a[i];
minnegi = i;
}
}
}
else if(a[i] == 0) // a[i] is zero
{
zeroi = i;
if(++n_zero > 1) return 0;
}
else // a[i] is positive
{
n_pos++;
if(minpos == 0)
{
minpos = a[i];
minposi = i;
}
else if(minpos > a[i])
{
minpos = a[i];
minposi = i;
}
}
}
if (n_zero){
printf("zeros.\n");
if (n_neg & 1)
return 0;
else
out = zeroi;
}
else {
printf("no zero.\n");
if (n_neg & 1)
out = maxnegi;
else if (n_pos == 0){
out = minnegi;
}
else {
out = minposi;
}
}
for(int i = 0; i < n; i++)
{
max *= (i == out) ? 1 : a[i];
}
return max;
}
void show(int a[],int n)
{
for(int i = 0; i < n; i++){
printf("%-3d",a[i]);
}
printf("\n");
}
int main()
{
int a[6];
int N = 6;
srand(time(NULL));
for(int i = 0; i < N; i++){
a[i] = rand() % 10 ;
if (a[i] & 0x1)
a[i] = -a[i];
}
show(a,N);
printf("Max Sub Product of N-1 elements: %d .\n",MaxSubProducti(a,N));
printf("Max Sub Product of N-1 elements: %d .\n",MaxSubProductii(a,N));
printf("Max Sub Product of N-1 elements: %d .\n",MaxSubProductiii(a,N));
printf("Max Sub Product of N-1 elements: %d .\n",MaxSubProductiv(a,N));
printf("Max Sub Product of N-1 elements: %d .\n",MaxSubProductv(a,N));
}
测试输出:
2 -5 -5 -5 -7 2
Max Sub Product of N-1 elements: 1750 .
Max Sub Product of N-1 elements: 1750 .
Max Sub Product of N-1 elements: 1750 .
no zero and even negatives
Max Sub Product of N-1 elements: 1750 .
no zero.
Max Sub Product of N-1 elements: 1750 .
REF:
1,编程之美 2.13