【问题标题】:Find the largest sum including at most two consecutive elements from an array从数组中找到最多包含两个连续元素的最大和
【发布时间】:2013-08-27 13:00:31
【问题描述】:

我一直在玩一些算法来获得最大和,而数组中没有两个相邻元素,但我在想:

如果我们有一个包含 n 个元素的数组,并且我们想找到最大的和,这样 3 个元素就不会接触。也就是说,如果我们有数组 a = [2, 5, 3, 7, 8, 1],我们可以选择 2 和 5,但不能选择 2、5 和 3,因为这样我们就有 3 个连续。此数组的这些规则的最大总和为:22(2 和 5、7 和 8。2+5+7+8=22)

我不确定我将如何实现它,有什么想法吗?

编辑:

我只是想了想做什么可能是好的:

让我们坚持同一个数组:

int[] a = {2, 5, 3, 7, 8, 1};
int{} b = new int[n}; //an array to store results in
int n = a.length;
// base case
b[1] = a[1];
// go through each element:
for(int i = 1; i < n; i++)
{
    /* find each possible way of going to the next element
    use Math.max to take the "better" option to store in the array b*/
}
return b[n]; // return the last (biggest) element.

这只是我脑海中的一个想法,没有比这更长的时间。

【问题讨论】:

  • 向我们展示您的尝试
  • 我没有在代码中放任何东西,只是在想这个。基本情况当然是第一个元素,其余的我认为最好将我已经拥有的结果存储在一个数组中。然后我可以将数组中的内容与 Math.max(possibility1+Array[latest-element],可能性2+Array[latest-2-element]) 进行比较,因为在去那里之前你不知道接下来会出现什么元素。将其放在 for 循环中以遍历数字数组。但我的想法只有这么“远”。

标签: java arrays algorithm


【解决方案1】:

没有两个元素相邻的最大和算法:
循环 arr[] 中的所有元素并保持两个总和 incl 和 excl 其中 incl = 包括前一个元素的最大总和,excl = 不包括前一个元素的最大总和。

不包括当前元素的最大和为max(incl, excl),包括当前元素的最大和为excl + 当前元素(注意,只考虑excl,因为元素不能相邻)。

在循环结束时返回包含和排除的最大值。

实施:

#include<stdio.h>

/*Function to return max sum such that no two elements
 are adjacent */
int FindMaxSum(int arr[], int n)
{
  int incl = arr[0];
  int excl = 0;
  int excl_new;
  int i;

  for (i = 1; i < n; i++)
  {
     /* current max excluding i */
     excl_new = (incl > excl)? incl: excl;

     /* current max including i */
     incl = excl + arr[i];
     excl = excl_new;
  }

   /* return max of incl and excl */
   return ((incl > excl)? incl : excl);
}

/* Driver program to test above function */
int main()
{
  int arr[] = {5, 5, 10, 100, 10, 5};
  printf("%d \n", FindMaxSum(arr, 6));
  getchar();
  return 0;
}

时间复杂度:O(n)
空间复杂度:O(1)


编辑 1:
如果你理解了上面的代码,我们可以很容易地通过维护之前位置已经相邻的数字的计数来解决这个问题。 这是所需问题的有效实现

//We could assume we store optimal result upto i in array sum
//but we need only sum[i-3] to sum[i-1] to calculate sum[i]
//so in this code, I have instead maintained 3 ints
//So that space complexity to O(1) remains

#include<stdio.h>

int max(int a,int b)
{
    if(a>b)
        return 1;
    else
        return 0;
}

/*Function to return max sum such that no three elements
 are adjacent */
int FindMaxSum(int arr[], int n)
{
  int a1 = arr[0]+arr[1];//equivalent to sum[i-1]
  int a2 =arr[0];//equivalent to sum[i-2]
  int a3 = 0;//equivalent to sum [i-3]
  int count=2;
  int crr = 0;//current maximum, equivalent to sum[i]
  int i;
  int temp;

  for (i = 2; i < n; i++)
  {
      if(count==2)//two elements were consecutive for sum[i-1]
      {
          temp=max(a2+arr[i],a1);
          if(temp==1)
          {
              crr= a2+arr[i];
              count = 1;
          }
          else
          {
              crr=a1;
              count = 0;
          }
          //below is the case if we sould have rejected arr[i-2]
          // to include arr[i-1],arr[i]
          if(crr<(a3+arr[i-1]+arr[i]))
          {
              count=2;
              crr=a3+arr[i-1]+arr[i];
          }
      }
      else//case when we have count<2, obviously add the number
      {
          crr=a1+arr[i];
          count++;
      }
      a3=a2;
      a2=a1;
      a1=crr;
  }
  return crr;
}

/* Driver program to test above function */
int main()
{
  int arr[] = {2, 5, 3, 7, 8, 1};
  printf("%d \n", FindMaxSum(arr, 6));
  return 0;
}

时间复杂度:O(n)
空间复杂度:O(1)

【讨论】:

  • 这是确定没有两个相邻元素的最大数字的代码,我在想如果两个元素可以相邻,但不能超过或等于三个一排。 :)
  • @Zanii:没关系,它可以很容易地推广到任意数量的允许相邻元素,请参阅下面的答案。 (Ps. +1 向 adi 寻求灵感。)
  • 这不能回答问题。这回答了“最大和使得没有两个元素相邻”的问题。但是,这篇文章中提出的问题是“从一个数组中找到最多包括两个连续元素的最大总和”。此答案不允许添加相邻元素,但本文中的问题最多允许添加 2 个连续的相邻元素。为什么这么多人点赞?
  • 请查看添加的代码,主要技巧保持不变。只是病例数增加了。测试 {1, 4, 3, 2, 6, 5} 和 {2, 5, 3, 7, 8, 1}
  • @adi 好更新。虽然不能自己测试。希望其他人可以确认。
【解决方案2】:

adi's solution 可以很容易地概括为允许最多 n 个相邻元素包含在总和中。诀窍是维护一个 n + 1 个元素的数组,其中数组中的第 k 个元素 (0 ≤ kn) 给出最大和,假设 k 个先前的输入包含在总和中,而 k+1-th 不包含:

/**
 * Find maximum sum of elements in the input array, with at most n adjacent
 * elements included in the sum.
 */
public static int maxSum (int input[], int n) {
    int sums[] = new int[n+1];  // new int[] fills the array with zeros
    int max = 0;

    for (int x: input) {
        int newMax = max;
        // update sums[k] for k > 0 by adding x to the old sums[k-1]
        // (loop from top down to avoid overwriting sums[k-1] too soon)
        for (int k = n; k > 0; k--) {
            sums[k] = sums[k-1] + x;
            if (sums[k] > newMax) newMax = sums[k];
        }
        sums[0] = max;  // update sums[0] to best sum possible if x is excluded
        max = newMax;   // update maximum sum possible so far
    }
    return max;
}

和 adi 的解决方案一样,这个也是线性时间运行的(准确地说,O(mn),其中 m 是输入的长度, n 是总和中允许的最大相邻元素数)并使用与输入长度无关的恒定内存量(O(n))。事实上,它甚至可以很容易地修改为处理预先不知道长度的输入流。

【讨论】:

  • 如果我输入数组 [1, 4, 3, 2, 6, 5] 我得到 21 当答案应该是 18: _ 4 3 _ 6 5. 但是如果你添加所有元素加在一起,你得到 21。如果我添加我在示例中的数组 ([2, 5, 3, 7, 8, 1]),我得到 26 而不是 22,如果你把所有元素加在一起,你得到 26 .
  • @Zanii:奇怪。 It works for me. 您是否传入了正确的 n 值(即您的情况为 2)?
  • 是的,这就是问题所在,我只是没看清楚评论。
【解决方案3】:

我会想象将数组按该顺序放入二叉树中。这样您就可以跟踪哪个元素彼此相邻。然后只需简单地做一个 if(节点不直接相互链接)来对不相邻的节点求和。您可以通过递归来实现并返回最大数量,从而使事情更容易编码。希望能帮助到你。

【讨论】:

    【解决方案4】:

    对于具有n 条目的集合,有2^n 方法对其进行分区。因此,要生成所有可能的集合,只需从 0:2^n-1 循环并从数组中选择那些条目设置为 1 的元素(请耐心等待;我正在回答你的问题):

    max = 0;
    for (i = 0; i < 1<<n; ++i) {
      sum = 0;
      for (j = 0; j < n; ++j) {
        if (i & (1<<j)) { sum += array[j]; }
      }
      if (sum > max) { /* store max and store i */ }
    }
    

    这将找到对数组条目求和的最大方法。现在,您想要的问题是您不想允许 i 的所有值 - 特别是那些包含 3 个连续 1 的值。这可以通过测试号码7 (b111) 在任何位移时是否可用来完成:

    for (i = 0; i < 1<<n; ++i) {
      for (j = 0; j < n-2; ++j) {
        if ((i & (7 << j)) == (7 << j)) { /* skip this i */ }
      }
      ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-31
      • 2014-02-15
      • 1970-01-01
      • 2023-04-05
      • 2016-05-14
      • 1970-01-01
      • 2015-11-08
      • 2018-01-03
      相关资源
      最近更新 更多