【问题标题】:Range of maximum product subarray (Kadane algorithm variant)最大乘积子数组的范围(Kadane 算法变体)
【发布时间】:2014-07-14 19:10:09
【问题描述】:

我一直在尝试获取子数组的最大乘积的范围(为求职面试而学习)。

这已在此处提出(但未提供有效答案)。 Getting range of max product subarray using Kadanes algorithm

技巧/算法在这里解释得很好:http://www.geeksforgeeks.org/maximum-product-subarray/

我能够轻松获得最大产品,但经过多次尝试,仍然无法弄清楚如何获得范围(左右索引正确)。有人可以帮忙吗??

我已经粘贴了我的代码,所以你可以快速复制并运行它..

import java.util.*;

public class ArrayMax {

// maximum product
public static int[] getMaxProduct(int[] list)
{
    int max = 1, min = 1, maxProd = 0;
    int l = 0, left = 0, right = 0;

    for (int i = 0; i < list.length; i++) {

        // positive number!
        if (list[i] > 0) {
            max = max * list[i];
            min = Math.min(1, min * list[i]);
        }
        else if (list[i] == 0) {
            max = 1;    // reset all
            min = 1;
            l = i + 1;
        }
        else {
            // hold the current Max                                  
            int tempMax = max;
                     // need to update left here (but how??)
            max = Math.max(min * list[i], 1); // [-33, 3]
            min = tempMax * list[i];  // update min with prev max

        }

    //  System.out.printf("[%d %d]%n", max, min);       
        if (max >= maxProd) {
            maxProd = max;
            right = i;
            left = l;
        }
    }

    System.out.println("Max: " + maxProd);
    // copy array
    return Arrays.copyOfRange(list, left, right + 1);
}


// prints array
public static void printArray(int[] list) {

    System.out.print("[");
    for (int i = 0; i < list.length; i++) {     
        String sep = (i < list.length - 1) ? "," : "";
        System.out.printf("%d%s", list[i], sep);
    }

    System.out.print("]");
}

public static void main(String[] args) {

    int[][] list = {
        {5, 1, -3, -8},
        {0, 0, -11, -2, -3, 5},
        {2, 1, -2, 9}
    };

    for (int i = 0; i < list.length; i++) {
        int[] res = getMaxProduct(list[i]);

        printArray(list[i]);
        System.out.print(" => ");
        printArray(res);

        System.out.println();
    }
}
} 

以下是示例输出:

Max: 120
[5,1,-3,-8] => [5,1,-3,-8]
Max: 30
[0,0,-11,-2,-3,5] => [-11,-2,-3,5]
Max: 9
[2,1,-2,9] => [2,1,-2,9]

如您所见,我得到了最大的产品,但范围是错误的。

Case#2, Max is 30 (correct answer: [-2,-3,5], showing: [-11,-2,-3,5])
Case#3, Max is 9 (correct answer: [9], giving: [2,1,-2,9])

请帮忙。

【问题讨论】:

    标签: java algorithm sub-array kadanes-algorithm


    【解决方案1】:

    更简单的方法是在计算完 maxProd(最后)后尝试找到左侧位置/标记。您的正确位置是准确的,因此从左到右设置并将 maxProd 除以 list[left] 直到您达到 1,同时向左递减。那是你到达左边的时候。

    返回之前的以下代码应该可以解决它。

    int temp = maxProd;
    left = right;
    while (temp != 1) {
       temp = temp / list[left--];
    }
    left++;
    // copy array
    return Arrays.copyOfRange(list, left, right + 1);
    

    【讨论】:

    • 效果很好。谢谢。有一个小问题(没什么大不了的)。如果子数组的开头有连续的 1,例如:[1, 1, 5, 6, 9].. 这将返回 [5,6,9],这仍然是正确的:)。
    • @Sanjay 它有点重要,因为 [5,6,9] 不是最大的子数组,即使产品相同
    【解决方案2】:

    我认为您需要跟踪 l 的 2 个值。一个表示乘以得到最大值的数字子数组的起始索引,而另一个表示乘以得到最小值的数字子数组的起始索引。

    但是,更简单的方法是等到找到最大答案(在 maxProd 中)及其位置(在右侧)。此时,您可以循环遍历数组,将列表的元素相乘,直到总数达到 maxProd(从右侧开始并向后迭代)。您相乘的最后一个元素必须是子数组的开头。

    【讨论】:

    • 感谢您的解决方案。我已经接受了另一个选择的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2020-08-30
    • 2019-10-13
    相关资源
    最近更新 更多