Maximum product of consecutive subsequence(最大连续子序列乘积)

最大连续子序列乘积

简单版: 给定一定长度的序列x1,x2,x3,x4…..xn(不考虑负数), 找出其中连续子序列乘积的最大值。比如给定2,0.1,6,7。其中最大连续子序列乘积为42,就是6和7的乘积。也即是如果可以找到连续子序列的下标就可以知道最大值。这里6和7的下标分别为2和3。
如果采用蛮力方式,那么需要枚举出所有可能的连续子序列,上例中,需要列出2*0.1,2*0.1*6,2*0.1*6*7, 0.1*6, 0.1*6*7, 6*7. 故不能采用这种方式。
这里采用动态规划的思路来解决此问题,F[k] = max{F[k − 1] × xk; xk},即F[K]是包含下标为k的最大连续子序列的乘积。在利用S[k]来记录下标,这里只用记录0或者1。1表示改元素在最大子序列中,0表示不在。这样我们遍历一遍数组即可找出最大连续子序列乘积所包含的下标了。具体代码如下:

    public static void max(double[] a){
    int[] s = new int[a.length];
    double[] f = new double[a.length];
    f[0] = a[0];
    s[0] = 1;
    int p = 1;
    int j = 0;
    double max = f[0];

    for(int i = 1;i<a.length;i++){
        if(f[i-1]*a[i]>a[i]){
            f[i] = f[i-1]*a[i];
            s[i] = 1;
        }else{
            f[i] = a[i];
            s[i] = 0;
        }
        if(f[i] >max){
            p = i;
            max = f[i];
        }
    }
    j = p;

    System.out.println(j);  
    while(s[j]==1){
        j = j - 1;
        System.out.println(j);
    }       
}

再深入考虑下如果存在负数的话,那么可能会出现前面子序列乘积的值是负的,但是后一个值k也是负的,这样反而负负得正,可能产生最大值。所以在遍历的过程中吗,需要保存最大值和最小值。下面两个表达式就是记录最大值和最小值的。


max[i] = max(max(a[i], max[i-1]*a[i]), min[i-1]*a[i]);
min[i] = min(min(a[i], max[i-1]*a[i]), min[i-1]*a[i]);

之后只需要将原先的最大值和最后的max[i],比较返回较大的即可。具体代码如下:

    public static double max(double a, double b){
    return (a>b)? a:b;
}
public static double min(double a, double b){
    return (a < b) ? a : b;
}
public static double MMS(double[] a){
    double[] max = new double[a.length];
    double[] min = new double[a.length];   
    double res;
    max[0] = min[0] = a[0];
    res = a[0];
    for (int i = 1; i < a.length; i++){
        max[i] = max(max(a[i], max[i-1]*a[i]), min[i-1]*a[i]);
        min[i] = min(min(a[i], max[i-1]*a[i]), min[i-1]*a[i]);
        res = max(res, max[i]);
    }
    return res;
}

这里直接返回了最大值,而不是对应元素的下标。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值