在整数数组中查找具有最大乘积的连续序列

时间:2011-05-12 06:08:35

标签: c# .net arrays algorithm

我已经提出了下面的代码,但这并不能满足所有情况,例如:

  1. 包含全0的数组

  2. 具有负值的数组(它有点棘手,因为它是关于找到产品为两个负值的正值)

    public static int LargestProduct(int[] arr)
    {   
        //returning arr[0] if it has only one element
        if (arr.Length == 1) return arr[0];
    
        int product = 1;
        int maxProduct = Int32.MinValue;
    
        for (int i = 0; i < arr.Length; i++)
        {
            //this block store the largest product so far when it finds 0 
            if (arr[i] == 0)
            {
                if (maxProduct < product)
                {
                    maxProduct = product;
                }
                product = 1;
            }
            else 
            {
                product *= arr[i];
            }
        }
        if (maxProduct > product)
            return maxProduct;
        else
            return product;
    }
    
  3. 如何合并上述案例/更正代码。请建议。

5 个答案:

答案 0 :(得分:2)

我的答案基于这样的假设:如果你在数组中有超过1个元素,你需要乘以至少2个连续的整数来检查输出,即在{-1,15}的数组中,你想要的输出是-15而不是15)。

我们需要解决的问题是查看所有可能的乘法组合,并找出它们中的最大乘积。

n个整数数组中的乘积总数为nC2,即如果有2个元素,那么总乘法组合将为1,对于3,它将为3,对于4,它将为6,因此上。

对于我们在传入数组中的每个数字,它必须与我们对最后一个元素进行的所有乘法相乘并保持最大乘积直到现在如果我们为所有元素执行,最后我们将保留最大产品。

这应该适用于否定和零。

    public static long LargestProduct(int[] arr)
    {
        if (arr.Length == 1)
            return arr[0];

        int lastNumber = 1;
        List<long> latestProducts = new List<long>();
        long maxProduct = Int64.MinValue;
        for (int i = 0; i < arr.Length; i++)
        {
            var item = arr[i];
            var latest = lastNumber * item;
            var temp = new long[latestProducts.Count];
            latestProducts.CopyTo(temp);
            latestProducts.Clear();
            foreach (var p in temp)
            {
                var product = p * item;
                if (product > maxProduct)
                    maxProduct = product;
                latestProducts.Add(product);
            }
            if (i != 0)
            {
                if (latest > maxProduct)
                    maxProduct = latest;
                latestProducts.Add(latest);
            }
            lastNumber = item;
        }
        return maxProduct;
    }

如果您希望最大产品也包含数组中存在的单个元素,即{-1,15}应该写成15,那么您可以将最大乘积与正在处理的数组的元素进行比较,这应该给你如果单个元素是最大数,则为最大乘积。 这可以通过在最后的for循环中添加以下代码来实现。

if (item > maxProduct)
    maxProduct = item;

答案 1 :(得分:1)

你的基本问题是2部分。分解它们并解决它变得更容易。

1)查找所有连续的子集。

由于您的源序列可能具有负值,因此在您找到每个子集之前,您并不是唯一能够进行任何值判断的装备,因为否定值可以在以后被另一个子集“取消”。所以让第一阶段只找到子集。

如何执行此操作的示例是以下代码

// will contain all contiguous subsets 
var sequences = new List<Tuple<bool, List<int>>>();

// build subsets 
foreach (int item in source)
{
    var deadCopies = new List<Tuple<bool, List<int>>>();

    foreach (var record in sequences.Where(r => r.Item1 && !r.Item2.Contains(0)))
    {
        // make a copy that is "dead"
        var deadCopy = new Tuple<bool, List<int>>(false, record.Item2.ToList());
        deadCopies.Add(deadCopy);

        record.Item2.Add(item);
    }

    sequences.Add(new Tuple<bool, List<int>>(true, new List<int> { item }));
    sequences.AddRange(deadCopies);
}

在上面的代码中,我正在构建所有连续的子集,同时冒昧地不向已经具有0值的给定子集添加任何内容。如果您愿意,可以省略该特定行为。

2)计算每个子集的产品并将其与最大值进行比较。

找到所有符合条件的子集后,下一部分就很容易了。

// find subset with highest product 
int maxProduct = int.MinValue;
IEnumerable<int> maxSequence = Enumerable.Empty<int>();

foreach (var record in sequences)
{
    int product = record.Item2.Aggregate((a, b) => a * b);
    if (product > maxProduct)
    {
        maxProduct = product;
        maxSequence = record.Item2;
    }
}

添加您希望限制原始源或候选子集或产品值的长度的任何逻辑。例如,如果您希望对其中任何一个强制执行最小长度要求,或者如果非零产品可用,则允许子集乘积为0。

此外,我没有声明代码的性能,只是为了说明将问题分解为部分。

答案 2 :(得分:0)

我认为你应该同时拥有两种产品 - 它们的标志会有所不同。 关于大小写,当所有值都为零时 - 你可以在最后检查maxProduct是否仍然是Int32.MinValue(如果真的无法使用Int32.MinValue) 我的变种:

int maxProduct = Int32.MinValue;
int? productWithPositiveStart = null;
int? productWithNegativeStart = null;

for (int i = 0; i < arr.Length; i++)
    {
        if (arr[i] == 0)
        {
            productWithPositiveStart = null;
            productWithNegativeStart = null;
        } 
        else 
        {
            if (arr[i] > 0 && productWithPositiveStart == null) 
            {
                 productWithPositiveStart = arr[i];            
            }
            else if (productWithPositiveStart != null)
            {
                 productWithPositiveStart *= arr[i];
                 maxProduct = Math.max(maxProduct, productWithPositiveStart);
            }
            if (arr[i] < 0 && productWithNegativeStart == null)
            {
                 productWithNegativeStart = arr[i];
            }
            else if (productWithNegativeStart != null) 
            {
                 productWithNegativeStart *= arr[i];
                 maxProduct = Math.max(maxProduct, productWithNegativeStart);
            }
            maxProduct = Math.max(arr[i], maxProduct);
        }            
    }
 if (maxProduct == Int32.MinValue) 
 {
     maxProduct = 0;
 }

答案 3 :(得分:0)

在较高级别,您当前的算法将数组拆分为0并返回这些子数组的最大连续乘积。任何进一步的迭代都将在找到子数组中最大的连续乘积的过程中,其中没有元素为0。

考虑到负数,我们显然首先需要测试其中一个子阵列的产品是否为负数,如果是,则采取一些特殊措施。

否定结果来自奇数个负值,因此我们需要删除其中一个负值以使结果再次为正。为此,我们删除第一个负数上的所有元素,或最后一个负数以及之后的所有元素,以最高乘积为准。

要考虑所有0的数组,只需使用0作为起始maxProduct。如果数组是单个负值,则对单个元素进行特殊处理将意味着返回。之后,总会有一个正的子序列产品,否则整个数组都是0,无论如何都应该返回0。

答案 4 :(得分:0)

可以在O(N)中完成。它基于一个简单的想法:计算最小值(minCurrent)和最大值(maxCurrent)直到i。这可以很容易地改变,以适应如下条件:{0,0,-2,0} or {-2,-3, -8} or {0,0}

<强> a[] = {6, -3, 2, 0, 3, -2, -4, -2, 4, 5}

<强> steps of the algorithm given below for the above array a :

private static int getMaxProduct(int[] a) {
    if (a.length == 0) {
        throw new IllegalArgumentException();
    }
    int minCurrent = 1, maxCurrent = 1, max = Integer.MIN_VALUE;
    for (int current : a) {
        if (current > 0) {
            maxCurrent = maxCurrent * current;
            minCurrent = Math.min(minCurrent * current, 1);
        } else if (current == 0) {
            maxCurrent = 1;
            minCurrent = 1;
        } else {
            int x = maxCurrent;
            maxCurrent = Math.max(minCurrent * current, 1);
            minCurrent = x * current;
        }
        if (max < maxCurrent) {
            max = maxCurrent;
        }
    }
    //System.out.println(minCurrent);
    return max;
}