最大总和使得没有两个元素相邻

时间:2017-12-07 03:33:11

标签: arrays algorithm data-structures

现在可用的解决方案是包含排除总和。最后max这两个将给我输出。

现在最初我很难理解这个算法,我想为什么不以简单的方式进行。

ALGO: 通过一次增加两个数组指针

来遍历数组
  1. 计算数组
  2. 中的奇数定位元素sum
  3. 计算偶数定位元素sum
  4. 最后,取这两个max中的sum

    以这种方式,我认为复杂性将减少到一半O(n/2)

    这个算法是否正确

2 个答案:

答案 0 :(得分:2)

这是动态编程的一个例子。算法是:

  1. 不要采取(总结)任何非正面物品
  2. 对于正数,请将问题分成两部分:尝试执行滑动项目并返回以下选项的最大值:
  3. 让我们展示第二步,假设我们得到了:

    [1, 2, 3, 4, 5, 6, 10, 125, -8, 9]
    

    1是积极的,这就是为什么

    take_sum = max(1 + max_sum([3, 4, 5, 6, 10, 125, -8, 9])) // we take "1"
    skip_sum = max_sum([2, 3, 4, 5, 6, 10, 125, -8, 9])       // we skip "1" 
    max_sum =  max(take_sum, skip_sum)
    

    C#实现(最简单的代码,以显示裸体的想法,没有进一步的优化):

    private static int BestSum(int[] array, int index) {
      if (index >= array.Length)
        return 0;
    
      if (array[index] <= 0)
        return BestSum(array, index + 1);
    
      int take = array[index] + BestSum(array, index + 2);
      int skip = BestSum(array, index + 1);
    
      return Math.Max(take, skip);
    }
    
    private static int BestSum(int[] array) {
      return BestSum(array, 0);
    }
    

    <强>测试

    Console.WriteLine(BestSum(new int[] { 1, -2, -3, 100 }));
    Console.WriteLine(BestSum(new int[] { 100, 8, 10, 20, 7 }))
    

    <强>结果:

    101        
    120
    

    请检查您的初始算法是否返回次优总和的98117

    修改:在现实生活中,您可能需要添加一些优化,例如 memoization 和特殊情况测试:

    private static Dictionary<int, int> s_Memo = new Dictionary<int, int>();
    
    private static int BestSum(int[] array, int index) {
      if (index >= array.Length)
        return 0;
    
      int result;
    
      if (s_Memo.TryGetValue(index, out result)) // <- Memoization
        return result;
    
      if (array[index] <= 0) 
        return BestSum(array, index + 1);
    
      // Always take, when the last item to choose or when followed by non-positive item
      if (index >= array.Length - 1 || array[index + 1] <= 0) {
        result = array[index] + BestSum(array, index + 2);
      }
      else {
        int take = array[index] + BestSum(array, index + 2);
        int skip = BestSum(array, index + 1);
    
        result = Math.Max(take, skip);
      }
    
      s_Memo.Add(index, result); // <- Memoization
    
      return result;
    }
    
    private static int BestSum(int[] array) {
      s_Memo.Clear();
    
      return BestSum(array, 0);
    }
    

    <强>测试

      using System.Linq;
    
      ...
    
      Random gen = new Random(0); // 0 - random, by repeatable (to reproduce the same result)
    
      int[] test = Enumerable
        .Range(1, 10000)
        .Select(i => gen.Next(100))
        .ToArray();
    
      int evenSum = test.Where((v, i) => i % 2 == 0).Sum();
      int oddSum = test.Where((v, i) => i % 2 != 0).Sum();
      int suboptimalSum = Math.Max(evenSum, oddSum); // <- Your initial algorithm
      int result = BestSum(test);
    
      Console.WriteLine(
        $"odd: {oddSum} even: {evenSum} suboptimal: {suboptimalSum} actual: {result}");
    

    <强>结果:

      odd: 246117 even: 247137 suboptimal: 247137 actual: 290856
    

答案 1 :(得分:0)

动态编程包含排除方法是正确的你的算法不适用于测试用例如3 2 7 10在这个测试用例中我们采用的两个元素是3 10和sum是13而不是3,7或2,10.may你明白我在说什么,为了进一步清晰,代码在下面

Java实施

public int maxSum(int arr[]) {   // array must contain +ve elements only
 int excl = 0;
 int incl = arr[0];
 for (int i = 1; i < arr.length; i++) {
   int temp = incl;
   incl = Math.max(excl + arr[i], incl);
   excl = temp;
 }
 return incl;
}