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;ia[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;
}

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

你可能感兴趣的:(算法-Algorithm)