给定一个整数数组。找到MAXIMUM总和最大的子阵列

时间:2011-08-23 10:06:05

标签: c# .net algorithm

您好我正在准备面试代码测试,我偶然发现了这个问题。我尝试在C#尝试它,下面是我的尴尬答案,我甚至不知道它是否正确,但大多数情况下我猜不是,有人可以请我提供答案,这样当我重新处理解决方案时,我至少可以验证输出的答案。感谢。

示例数据:

int[] arr = {5, 1, -7, 3, 7};

代码:

int[] LargestsubarrayMaxSum(int[] arr)
{
    int temp = 0;
    int[] resultArr = new int[arr.Length];

    for (int i = 0; i < arr.Length - 1; i++)
    {
        if (i != 0)
        {
            foreach (int item in resultArr)
            {
                temp += item;
            }

            if (temp + arr[i + 1] > 0)
            {
                resultArr[i + 1] = temp + arr[i + 1];
            }
        }
        else
        {
            if ((arr[i] + arr[i + 1]) >= 0)
            {
                resultArr[i] = arr[i];
                resultArr[i + 1] = arr[i] + arr[i + 1];
            }
            else
            {
                resultArr[i] = arr[i];
                resultArr[i + 1] = 0;
            }
        }
    }
    return resultArr;
}

10 个答案:

答案 0 :(得分:9)

这个怎么样?

var arr = new [] {5, 1, -7, 3, 7};

var xs =
    from n in Enumerable.Range(0, arr.Length)
    from l in Enumerable.Range(1, arr.Length - n)
    let subseq = arr.Skip(n).Take(l)
    orderby subseq.Count() descending
    orderby subseq.Sum() descending
    select subseq;

var maxSumSubseq = xs.First();

编辑:添加orderby subseq.Count() descending以获得最大长度子序列。


编辑:根据评论添加了解释。

  1. 选择所有可能的子序列起始索引:

    from n in Enumerable.Range(0, arr.Length)
    
  2. 在给定起始索引的情况下选择所有可能的子序列长度:

    from l in Enumerable.Range(1, arr.Length - n)
    
  3. 从数组中提取子序列:

    let subseq = arr.Skip(n).Take(l)
    
  4. 按下降长度(即最长的第一个)排序子序列 - 可以按l而不是subseq.Count()排序,但后者更具表现力,即使前者效率更高:

    orderby subseq.Count() descending
    
  5. 计算每个子序列的总和并对子序列进行排序,因此最高值的总和是第一个:

    orderby subseq.Sum() descending
    
  6. 选择子序列:

    select subseq;
    
  7. 只选择第一个子序列 - 它是具有最大长度的最高值总和:

    xs.First();
    
  8. 希望这有帮助。

答案 1 :(得分:7)

O(N)时间复杂度和O(1)空间复杂度。这是我所知道的最佳解决方案:

#include <stdio.h>
#include <limits.h>

int get_max_sum(int* array, int len, int* start, int* end)
{
    int max_sum = INT_MIN, sum = 0, i;
    int tmp_start = 0;

    for(i = 0; i != len; ++i)
    {
        sum += array[i];

        // if the sum is equal, choose the one with more elements
        if(sum > max_sum || (sum == max_sum && (end - start) < (i - tmp_start)))
        {
            max_sum = sum;
            *start = tmp_start;
            *end = i;
        }
        if(sum < 0)
        {
            sum = 0;
            tmp_start = i + 1;
        }
    }

    return max_sum;
}

以下是一些测试用例:

int main(int argc, char **argv)
{
    int arr1[] = {5, 1, -7, 3, 7};
    int arr2[] = {1};
    int arr3[] = {-1, -7, -3, -7};
    int arr4[] = {5, 1, -7, 2, 2, 2};
    int start, end, sum;

    sum = get_max_sum(arr1, 5, &start, &end);
    printf("sum: %d, start: %d, end: %d\n", sum, start, end);

    sum = get_max_sum(arr2, 1, &start, &end);
    printf("sum: %d, start: %d, end: %d\n", sum, start, end);

    sum = get_max_sum(arr3, 4, &start, &end);
    printf("sum: %d, start: %d, end: %d\n", sum, start, end);

    sum = get_max_sum(arr4, 6, &start, &end);
    printf("sum: %d, start: %d, end: %d\n", sum, start, end);

    return 0;
}

$ ./a.out
sum: 10, start: 3, end: 4
sum: 1, start: 0, end: 0
sum: -1, start: 0, end: 0
sum: 6, start: 3, end: 5

<强> UPDATE1 : 添加了代码来打印子数组的索引。

<强> UPDATE2 : 如果找到具有相同总和的两个子数组,请选择具有更多元素的子数组。

<强> UPDATE3 : 修复导致负数的算法

答案 2 :(得分:4)

您可以使用Enigmativity的答案,但可以添加subseq.Count() descending的额外订单

或者如果你想要一个疯狂的linq查询......

int[] arr = .......

var result = new[]{0}
             .Concat(arr.Select((x,i)=>new {x,i})
             .Where(a=>a.x<0).Select(a=>a.i+1))
             .Select (i => arr.Skip(i).TakeWhile(a => a>=0))
             .OrderByDescending(a=>a.Sum())
             .OrderByDescending(a=>a.Count()).First();

但是通常你想把它们做成一个循环..

var result=new List<int>();
var maxResult=new List<int>();

// These next four variables could be calculated on the fly 
// but this way prevents reiterating the list each loop.
var count=0; 
var sum=0;
var maxCount=0;
var maxSum=0;

foreach (var value in arr) {
  if (value >=0) {
    result.Add(value);
    sum+=value;
    count++;
  } else {
    if (sum>maxSum || (sum==maxSum && count>maxCount)) {
      maxSum=sum;
      maxCount=count;
      maxResult=result;
    }
    result.Clear();
    count=0;
    sum=0;
  }
}

var returnValue=maxResult.ToArray();

答案 3 :(得分:1)

    public static int[] FindMaxArrayEx(int[] srcArray)
    {
        int[] maxArray = new int[1];
        int maxTotal = int.MinValue;
        int curIndex = 0;
        int tmpTotal = 0;
        List<int> tmpArray = new List<int>();

        if (srcArray.Length != 1)
        {
            for (int i = 0; i < srcArray.Length; i++)
            {
                tmpTotal = 0;
                curIndex = i;
                tmpArray.Clear();

                while (curIndex < srcArray.Length)
                {
                    tmpTotal += srcArray[curIndex];
                    tmpArray.Add(srcArray[curIndex]);

                    if (tmpTotal > maxTotal)
                    {
                        maxTotal = tmpTotal;
                        maxArray = tmpArray.ToArray();
                    }

                    curIndex++;
                }
            }
        }
        else
        {
            maxTotal = srcArray[0];
            maxArray = srcArray;
        }

        Console.WriteLine("FindMaxArrayEx: {0}",maxTotal);

        return maxArray;

    }

答案 4 :(得分:1)

这是一个完全可行的解决方案:

using System;
using System.Collections.Generic;

class MaxSumOfSubArray
{
    static void Main()
    {
        //int[] array = { 2, 3, -6, -1, 2, -1, 6, 4, -8, 8 };
        //maxSubSum(array);

        int digits;
        List<int> array = new List<int>();
        Console.WriteLine("Please enter array of integer values. To exit, enter eny key different than 0..9");

        while (int.TryParse(Console.ReadLine(), out digits))
        {
            array.Add(digits);
        }

        maxSubSum(array);
    }

    public static void maxSubSum(List<int> arr)
    {
        int maxSum = 0;
        int currentSum = 0;
        int i = 0;
        int j = 0;
        int seqStart=0;
        int seqEnd=0;
        while (j < arr.Count)
        {
            currentSum = currentSum + arr[j];

            if (currentSum > maxSum)
            {
                maxSum = currentSum;
                seqStart = i;
                seqEnd = j;
            }
            else if (currentSum < 0)
            {
                i = j + 1;
                currentSum = 0;
            }
            j++;
        }
        Console.Write("The sequence of maximal sum in given array is: {");
        for (int seq = seqStart; seq <= seqEnd; seq++)
        {
            Console.Write(arr[seq] + " ");
        }
        Console.WriteLine("\b}");
        Console.WriteLine("The maximum sum of subarray is: {0}", maxSum);
    }
}

答案 5 :(得分:1)

    /// <summary>
    /// given an non-empty input array of integers, this method returns the largest contiguous sum
    /// </summary>
    /// <param name="inputArray">the non-empty input array of integeres</param>
    /// <returns>int, the largest contiguous sum</returns>
    /// <remarks>time complexity O(n)</remarks>

    static int GetLargestContiguousSum(int[] inputArray)
    {
        //find length of the string, if empty throw an exception            
        if (inputArray.Length == 0)
            throw new ArgumentException("the input parameter cannot be an empty array");

        int maxSum = 0;
        int currentSum = 0;

        maxSum = currentSum = inputArray[0];
        for (int i = 1; i < inputArray.Length; i++) //skip i=0 as currentSum=inputArray[0].
        {
            currentSum = Math.Max(currentSum + inputArray[i], inputArray[i]);
            maxSum = Math.Max(currentSum, maxSum);
        }
        return maxSum;
    }

答案 6 :(得分:0)

/ * - 这是我在Wiki上发现的计算总和的算法,但要获得实际的子阵列              *我真的不得不思考。花了几个小时后,我能够使用startIndex解决它              * endIndex int变量然后通过添加if子句if(max_ending_here == array [i])                                 {startIndex = i; }              *这是非常艰难的。我希望你们都能根据需要进行重构以进行一些改进。* /

/*  Initialize:
            max_so_far = 0
            max_ending_here = 0

        Loop for each element of the array
            (a) max_ending_here = max_ending_here + a[i]
            (b) if(max_ending_here < 0)
                    max_ending_here = 0
            (c) if(max_so_far < max_ending_here)
                    max_so_far = max_ending_here
        return max_so_far*/

        using System;
        using System.Collections.Generic;
        using System.Linq;
        using System.Text;
        namespace ConsoleApplication3
        {
            class Program
            {
                static void Main(string[] args)
                {
                    int[] array = { -2, 1, -3, 4, -1, 2, 1, -5, 4 };
                    int[] largestSubArray;
                    largestSubArray = Max_Array(array);
                    Console.WriteLine();

                    Console.WriteLine("Subarray is :");
                    foreach (int numb in largestSubArray)
                        Console.WriteLine(numb);
                    Console.ReadKey();
                }

                //Max_Array function will calculate the largest contigent array
                //sum and then find out startIndex and endIndex of sub array
                //within for loop.Using this startIndex and endIndex new subarray
                //is created with the name of largestSubArray and values are copied                           
                //from original array. 

                public static int[] Max_Array(int[] array)
                {
                    int[] largestSubArray;
                    int max_so_far = 0, max_ending_here = 0, startIndex = 0,
                        endIndex = 0;

                    for (int i = 0, j = 0; i < array.Length; i++)
                    {
                        max_ending_here += array[i];

                        if (max_ending_here <= 0)
                        {
                            max_ending_here = 0;
                        }

                        if (max_ending_here == array[i])
                            { startIndex = i; }

                        if (max_so_far < max_ending_here)
                        {                                
                            max_so_far = max_ending_here;
                            endIndex = i;
                        }
                    }
                    Console.WriteLine("Largest sum is: {0}", max_so_far);

                    largestSubArray = new int[(endIndex - startIndex) + 1];
                    Array.Copy(array, startIndex, largestSubArray, 0, (endIndex - startIndex) + 1);
                    return largestSubArray;

                }
            }
        }
  

输出

Largest sum is: 6
'Subarray is:
4,
-1,
2,
1'

答案 7 :(得分:0)

一旦你完成它就不那么复杂了。我认为它起初倒退了,这有点原因。

  1. 如果所有数字都是正数(或0),则整个数组将是最大和的最大子数组。
  2. 现在,我们可以采用这个事实并将其应用于正数组或负数组,而是说我们要包含所有正数(或0)的子数组。
  3. 从最后开始,在你离开时总结。当你发现一个负数时,你认为,那个负数会使我的其余部分变得毫无价值吗?如果没有,你继续......但你也将那一点标记为当前最大总和(如果它大于最后一个当前最大总和)。
  4. 如果它们毫无价值,(即总和现在小于0),您就会知道索引右侧的所有内容现在都毫无价值。尽管如此,你仍然可以保留当前的最大金额。
  5. 从3开始使用新索引。跟踪当前最大金额和结束的指数。

答案 8 :(得分:0)

数组中具有最大总和的SubArray是没有最小元素元素的数组。所以排序吧。并删除最小元素。而已。 这适用于其仅正整数数组。否则,正元素的子阵列只是答案

答案 9 :(得分:0)

以下代码为我工作:

static void Main(string[] args)
        {
            string str = Console.ReadLine();
            int [] arr = Array.ConvertAll(str.Split(' '),int.Parse);
            int curSum = 0, maxSum = 0;
            curSum = maxSum = arr[0];
            for (int i = 1; i < arr.Length; i++)
            {
                curSum = Math.Max(curSum + arr[i], arr[i]);
                maxSum = Math.Max(curSum, maxSum);
            }
            Console.WriteLine("{0}", maxSum);
            Console.ReadKey();
        }

输入:-2 1 -3 4 -1 2 1 -5 4

O / P:6