每日一题(77) - 子数组的最大乘积
2013-08-20 16:21
357 查看
题目来自编程之美
题目
举例
-4,-2,-3,-1 中任意三个数的最大乘积为-6
思路(1)暴力法
具体来说,把N个组合全找出来,计算乘积。时间复杂度为O(n^2).
思路(2)空间换时间,使用数据预先保存部分乘积的结果
具体来说:
使用数组nArrLeftPdt[i]:保存下标[0,i]之间数的乘积
使用数组nArrRightPdt[i]:保存下标[i,nLen - 1]之间数的乘积
则,去掉下标为i的元素的乘积为nArrLeftPdt[i] * nArrRightPdt[i].
这样,利用这两个数组,可以在O(n)的时间内得出结果。
代码:
(1)N个元素的乘积为0
<1>若剩余N-1个元素的乘积为0,则所有N-1个元素的组合的乘积肯定为0。
<2>若剩余N-1个元素的乘积为正数,则最大乘积为该正数。
<3>若剩余N-1个元素的乘积为负数,则最大乘积为0。
(2)N个元素的乘积为正数(原文有错误,少了一种情况)
<1>若所有元素均为正,则去掉最小的正数即可
<2>若所有元素均为负,则去掉绝对值最大的负数(最小的负数)即可
<3>若元素有正有负,则去掉最小的正数即可
(3)N个元素的乘积为负数
<1>若所有元素均为负,则去掉最大的负数(绝对值最小的负数)即可
<2>若部分元素为负,则去掉最大的负数(绝对值最小的负数)即可
为了尽量减少乘法的次数,我们可以只记录正数负数和0的个数以及最大的正数和最小的负数,之后分析元素个数得出结果。
时间复杂度:O(n)
代码:
题目
举例
-4,-2,-3,-1 中任意三个数的最大乘积为-6
思路(1)暴力法
具体来说,把N个组合全找出来,计算乘积。时间复杂度为O(n^2).
思路(2)空间换时间,使用数据预先保存部分乘积的结果
具体来说:
使用数组nArrLeftPdt[i]:保存下标[0,i]之间数的乘积
使用数组nArrRightPdt[i]:保存下标[i,nLen - 1]之间数的乘积
则,去掉下标为i的元素的乘积为nArrLeftPdt[i] * nArrRightPdt[i].
这样,利用这两个数组,可以在O(n)的时间内得出结果。
代码:
#include <iostream> #include <assert.h> using namespace std; long FindMaxProduct(int nArr[],int nLen) { assert(nArr && nLen > 0); if (nLen == 1) { return -0x3f3f3f3f; } long* nArrLeftPdt = new long[nLen]; long* nArrRightPdt = new long[nLen]; //初始化 nArrLeftPdt[0] = nArr[0]; nArrRightPdt[nLen - 1] = nArr[nLen - 1]; for (int i = 1;i < nLen;i++) { nArrLeftPdt[i] = nArrLeftPdt[i - 1] * nArr[i]; nArrRightPdt[nLen - 1 - i] = nArrRightPdt[nLen - i] * nArr[nLen - 1 - i]; } //比较 long nMax = nArrRightPdt[1]; for (int i = 1;i < nLen - 1;i++) { nMax = max(nMax,nArrLeftPdt[i - 1] * nArrRightPdt[i + 1]); } nMax = max(nMax,nArrLeftPdt[nLen - 2]); return nMax; } int main() { int nLen = 4; //int nArr[4] = {4,2,3,1}; //int nArr[4] = {4,-2,-3,1}; //int nArr[4] = {-4,-2,-3,-1}; //int nArr[4] = {4,-2,-3,-1}; //int nArr[4] = {4,2,3,-1}; //int nArr[4] = {4,0,0,-1}; //int nArr[4] = {4,-2,0,-1}; int nArr[4] = {4,-2,0,1}; cout<<FindMaxProduct(nArr,nLen)<<endl; system("pause"); return 1; }思路(3)根据N个元素的乘积和正负0元素个数分析
(1)N个元素的乘积为0
<1>若剩余N-1个元素的乘积为0,则所有N-1个元素的组合的乘积肯定为0。
<2>若剩余N-1个元素的乘积为正数,则最大乘积为该正数。
<3>若剩余N-1个元素的乘积为负数,则最大乘积为0。
(2)N个元素的乘积为正数(原文有错误,少了一种情况)
<1>若所有元素均为正,则去掉最小的正数即可
<2>若所有元素均为负,则去掉绝对值最大的负数(最小的负数)即可
<3>若元素有正有负,则去掉最小的正数即可
(3)N个元素的乘积为负数
<1>若所有元素均为负,则去掉最大的负数(绝对值最小的负数)即可
<2>若部分元素为负,则去掉最大的负数(绝对值最小的负数)即可
为了尽量减少乘法的次数,我们可以只记录正数负数和0的个数以及最大的正数和最小的负数,之后分析元素个数得出结果。
时间复杂度:O(n)
代码:
#include <iostream> #include <assert.h> using namespace std; //计算N-1个数之积 int FindProduct(int nArr[],int nLen,int nExceptNum) { bool bFlag = false; int nPrt = 1; for (int i = 0;i < nLen;i++) { if (!bFlag && nArr[i] == nExceptNum) { bFlag = true; } else { nPrt *= nArr[i]; } } if (nLen == 1) { return 0; } else { return nPrt; } } int FindMaxProduct(int nArr[],int nLen) { assert(nArr && nLen > 0); int nPosiCount = 0; int nNegCount = 0; int nZeroCount = 0; int nMinPos = 0x3f3f3f3f; int nMinNeg = 0x3f3f3f3f; int nMaxNeg = -0x3f3f3f3f; for (int i = 0;i < nLen;i++) { if (nArr[i] == 0) { nZeroCount++; } else if (nArr[i] > 0)//正数 { nPosiCount++; nMinPos = min(nMinPos,nArr[i]); nPosiCount++; } else //负数 { nMaxNeg = max(nMaxNeg,nArr[i]); nMinNeg = min(nMinNeg,nArr[i]); nNegCount++; } } if (nZeroCount > 0)//N个元素乘积为0 { if (nZeroCount > 1) { return 0; } else if ((nNegCount & 1) == 0) //偶数个负数,乘积为正数 { return FindProduct(nArr,nLen,0); } else //奇数个负数,乘积最大为0 { return 0; } } else if (nNegCount & 1)//有奇数个负数,即所有数乘积为负数,去掉最大的负数 { return FindProduct(nArr,nLen,nMaxNeg); } else //有偶数个负数,即所有数乘积为正数 { if (nNegCount == nLen)//所有元素均为负,则去掉最小的负数 { return FindProduct(nArr,nLen,nMinNeg); } else//所有元素均为正或有正有负,则去掉最小的正数 { return FindProduct(nArr,nLen,nMinPos); } } } int main() { //int nLen = 4; //int nArr[4] = {4,2,3,1}; //int nArr[4] = {4,-2,-3,1}; //int nArr[4] = {-4,-2,-3,-1}; //int nArr[4] = {4,-2,-3,-1}; //int nArr[4] = {4,2,3,-1}; //int nArr[4] = {4,0,0,-1}; //int nArr[4] = {4,-2,0,-1}; //int nArr[4] = {4,-2,0,1}; int nLen = 1; //int nArr[1] = {0}; //int nArr[1] = {-1}; int nArr[1] = {1}; cout<<FindMaxProduct(nArr,nLen)<<endl; system("pause"); return 1; }
相关文章推荐
- 每日一练-----返回乘积最大的子数组的积
- 每日一个小算法(一) 数组中连续个数组成的和最大
- LeetCode OJ:Maximum Product Subarray(子数组最大乘积)
- 求子数组的最大乘积
- 【LeetCode-面试算法经典-Java实现】【152-Maximum Product Subarray(子数组的最大乘积)】
- LeetCode-152:Maximum Product Subarray (乘积最大连续子数组) -- medium
- 数组连续子数组最大和最大乘积
- 每日一题 一个整型数组,其中有正值有负值,请拿出其中相邻子数组中的最大值
- 子数组的最大乘积
- 【LeetCode】152. Maximum Product Subarray最大连续子数组乘积
- 最大乘积连续子序列(数组)//枚举法的大好江山
- 求数组中乘积最大的子串
- Maximum Subarray Maximum Product Subarray 子数组的最大和 最大乘积
- 笔试题 找到数组中,三个数乘积最大的结果
- LeetCode-628:Maximum Product of Three Numbers (数组三元素最大乘积)
- 每日一题(81) - 子数组之和的最大值(二维) - 最大子矩阵和
- 子数组的最大乘积问题
- 最大连续子数组和、乘积(动态规划)
- 数组最大连续乘积
- 数组的连续子数组之和最大值,子数组最大乘积,二维数组子数组之和