401最大连续乘积子串
2014-07-22 15:56
435 查看
题目:
给一个浮点数序列,取最大乘积连续子串的值,例如 -2.5,4,0,3,0.5,8,-1,则取出的最大乘积连续子串为3,0.5,8。也就是说,上述数组中,3 0.5 8这3个数的乘积3*0.5*8=12是最大的,而且是连续的。思路1:
暴力法:将所有的可能都罗列出来,时间复杂度为O(n^2)
double maxProductSubString(double *data, int n) { double maxResult = data[0]; for(int i=0;i<n;i++) { double x = 1; for(int j=i;j<n;j++) { x *= data[j]; if(x>maxResult) { maxResult = x; } } } return maxResult; }思路二:
利用动态规划的方法:由于在数组中有正数和负数,所以需要记录最大的乘积和最小的乘积,maxend和minend,最小乘积乘以一个负数可能成为最大乘积,利用状态转移方程进行计算:
maxend = max(max(maxend*a[i],minend*a[i]),a[i]);
minend = min (min(maxend*a[i],minend*a[i]),a[i]);
对于元素a[i],在0-i中,要么是与maxend相乘之后变为最大乘积,要么与minend相乘变成最大乘积,或者本身就是最大乘积。
初始化都为a[]
double maxProductsubString_dynamic(double *data, int n) { double maxend, minend; maxend = minend = data[0]; double result = data[0]; for(int i=1;i<n;i++) { double end1 = maxend*data[i],end2 = minend*data[i]; maxend = max(max(end1,end2),data[i]); minend = min(min(end1,end2),data[i]); result = max(maxend,result); } return result; }时间复杂度为O(n)
举一反三
1、给定一个长度为N的整数数组,只允许用乘法,不能用除法,计算任意(N-1)个数的组合中乘积最大的一组,并写出算法的时间复杂度。分析:我们可以把所有可能的(N-1)个数的组合找出来,分别计算它们的乘积,并比较大小。由于总共有N个(N-1)个数的组合,总的时间复杂度为O(N^2),显然这不是最好的解法。
int maxN_1ProductSubString(int *data, int n) { int maxResult=1; for(int k=1;k<n;k++) maxResult *= data[k]; for(int i=0;i<n;i++) { int produce = 1; for(int j=0;j<n;j++) { if(j != i) { produce *= data[j]; } } if(produce > maxResult) maxResult = produce; } return maxResult; }思路二:
一空间换时间,利用两个数组s[],t[],s[i]记录0-i元素的乘积,t[i]代表i-n-1元素的乘积,那么去除a[i]后的乘积是s[i-1]*t[i+1],由于只需要扫描两遍数组,所以时间复杂度是线性的O(n)
int maxN_1ProductSubString2(int *data, int const n) { int *s = new int ; int *t = new int ; s[0] = data[0]; t[n-1] = data[n-1]; for(int i=1;i<n;i++) { s[i] = s[i-1] * data[i]; } for(int j=n-2;j>=0;j--) { t[j] = t[j+1] * data[j]; } int maxResult = s[0] * t[2]; for(int i=1;i<n-1;i++) { int r = s[i-1] * t[i+1]; if(r > maxResult) maxResult = r; } return maxResult; }在上述的基础上,可以进行逻辑判断,减少计算量:
假设N个整数的乘积为P,针对P的正负性进行如下分析(其中,AN-1表示N-1个数的组合,PN-1表示N-1个数的组合的乘积)。
1.P为0
那么,数组中至少包含有一个0。假设除去一个0之外,其他N-1个数的乘积为Q,根据Q的正负性进行讨论:
Q为0
说明数组中至少有两个0,那么N-1个数的乘积只能为0,返回0;
Q为正数
返回Q,因为如果以0替换此时AN-1中的任一个数,所得到的PN-1为0,必然小于Q;
Q为负数
如果以0替换此时AN-1中的任一个数,所得到的PN-1为0,大于Q,乘积最大值为0。
2. P为负数
根据“负负得正”的乘法性质,自然想到从N个整数中去掉一个负数,使得PN-1为一个正数。而要使这个正数最大,这个被去掉的负数的绝对值必须是数组中最小的。我们只需要扫描一遍数组,把绝对值最小的负数给去掉就可以了。
3. P为正数
类似地,如果数组中存在正数值,那么应该去掉最小的正数值,否则去掉绝对值最大的负数值。
上面的解法采用了直接求N个整数的乘积P,进而判断P的正负性的办法,但是直接求乘积在编译环境下往往会有溢出的危险(这也就是本题要求不使用除法的潜在用意),事实上可做一个小的转变,不需要直接求乘积,而是求出数组中正数(+)、负数(-)和0的个数,从而判断P的正负性,其余部分与以上面的解法相同。
在时间复杂度方面,由于只需要遍历数组一次,在遍历数组的同时就可得到数组中正数(+)、负数(-)和0的个数,以及数组中绝对值最小的正数和负数,时间复杂度为O(N)。
#define MAX_Postive 100 #define MIN_Negative -100 int maxN_1ProductSubString3(int *data, int const n) { int *s = new int ; int *t = new int ; s[0] = data[0]; t[n-1] = data[n-1]; for(int i=1;i<n;i++) { s[i] = s[i-1] * data[i]; } for(int j=n-2;j>=0;j--) { t[j] = t[j+1] * data[j]; } int num_zero=0,num_postive=0,num_negative=0; int position_min_postive,position_max_negative,position_zero; int min_postive = MAX_Postive; int max_negative = MIN_Negative; for(int k=0;k<n;k++) { if(data[k]==0) { ++num_zero; position_zero = k; } else if(data[k]>0) { ++num_postive; if(data[k]< min_postive) { position_min_postive = k; min_postive = data[k]; } }else { ++num_negative; if(data[k]>max_negative) { position_max_negative = k; max_negative = data[k]; } } } int maxResult; if(num_zero != 0) { if(num_zero == 1) { if(num_negative % 2 ==0) { if(position_zero == 0) maxResult = t[1]; else if(position_zero == n-1) maxResult = s[n-2]; else maxResult = s[position_zero-1]*t[position_zero+1]; }else maxResult = 0; }else { maxResult = 0; } }else { if(num_negative %2 == 0) { if(position_min_postive == 0) maxResult = t[1]; else if(position_min_postive == n-1) maxResult = s[n-2]; else maxResult = s[position_min_postive-1]*t[position_min_postive+1]; }else { if(position_max_negative == 0) maxResult = t[1]; else if(position_max_negative == n-1) maxResult = s[n-2]; else maxResult = s[position_max_negative-1]*t[position_max_negative+1]; } } return maxResult; }
相关文章推荐
- 编程之法:面试和算法心得(最大连续乘积子串)
- 程序员编程艺术第二十八~二十九章:最大连续乘积子串、字符串编辑距离
- 程序员编程艺术第二十八~二十九章:最大连续乘积子串、字符串编辑距离
- 动态规划题目(三)——最大连续乘积子串
- 程序员编程艺术第二十八~二十九章:最大连续乘积子串、字符串编辑距离
- 算法学习(十二)最大连续乘积子串、字符串编辑距离
- UVa787 - Maximum Sub-sequence Product(最大连续乘积子串)
- 最大连续乘积子串
- 程序员编程艺术第二十八~二十九章:最大连续乘积子串、字符串编辑距离
- 【算法】最大连续乘积子串
- 最大连续乘积子串
- 第28章:最大连续乘积子串
- 最大乘积连续子串
- 1019 最大乘积连续子串
- 找出数组中的最大连续乘积子串
- 第二十八章:最大连续乘积子串
- 最大连续乘积子串
- 最大连续乘积子串
- 程序员编程艺术第二十八~二十九章:最大连续乘积子串、字符串编辑距离