少一个数的子序列的最大乘积
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
由此可得出下面的算法实现:
总的时间复杂度为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[]中正数、负数、零的个数即可分析问题了。
算法如下:
返回值更改了,当最大乘积是0时,函数返回-1;否则返回去掉的那个数在数组A[]中的下标。
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[]中的下标。
相关文章推荐
- 找出一个乘积最大的连续子序列
- 输入n个元素组成的序列S,你需要找出一个乘积最大的连续子序列。如果这个最大的乘积不是正数,应输出0(表示无解)。1<=18,-10<=Si<=10
- hdu1087(求一个长上升子序列,使其和最大)
- 将一个正整数拆分成若干个互不相同的正整数且乘积最大(JS)
- n个学生站成一排 网易面试题之每个学生有一个能力值 牛牛想从n个学生中选出k名学生 要求相邻学生编号不超过d使得这k个学生乘积最大
- LeetCode题库解答与分析——#152. 乘积最大子序列MaximumProductSubarray
- 一个向量的最大子序列
- 给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大 java实现
- 给定一个无序数组,包含正数、负数和0,要求从中找出3个数的乘积,使得乘积最大
- 一个正整数N,拆成任意个正整数之和,怎样使这些数的乘积最大
- n个学生站成一排 网易面试题之每个学生有一个能力值 牛牛想从n个学生中选出k名学生 要求相邻学生编号不超过d使得这k个学生乘积最大
- N个整数,求其中任意N-1个数的乘积中的最大的一个
- 把一个包含n个正整数的序列划分成m个连续的子序列。设第i个序列的各数之和为S(i),求所有S(i)的最大值的最小值是多少?
- n个学生站成一排 网易面试题之每个学生有一个能力值 牛牛想从n个学生中选出k名学生 要求相邻学生编号不超过d使得这k个学生乘积最大
- 一个正整数n被分成若干个不同自然数的和,求组成n的一组自然数的最大乘积
- 求一个不含0的数列(可以有正数和负数)的最大子序列乘积java
- 将一个整数拆分使其乘积最大
- PAT 1096. Consecutive Factors (20)(最大连续乘积因子)(sqrt(n)判断一个数是否为质数的深刻理解)
- n个学生站成一排 网易面试题之每个学生有一个能力值 牛牛想从n个学生中选出k名学生 要求相邻学生编号不超过d使得这k个学生乘积最大
- 贪心算法——输入任意一个正整数N,将其分成多个互不相同的整数,和为N,乘积最大