我一直在玩一些算法来获得最大的总和,但阵列中没有两个相邻的元素,但我在想:
如果我们有一个包含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.
这只是我头脑中的一个想法,没有达到这个时间。
答案 0 :(得分:6)
最大和的算法,使得没有两个元素相邻:
为arr []中的所有元素循环并保持两个和,包括和excl其中incl =最大总和包括前一个元素和excl =最大总和,不包括前一个元素。
除当前元素之外的最大总和将是max(incl,excl),包括当前元素的最大总和将是excl + current元素(注意,只考虑excl因为元素不能相邻)。
在循环结束时返回最大值incl和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)
答案 1 :(得分:5)
adi's solution可以很容易地推广,以允许最多 n 相邻元素包含在总和中。诀窍是维护一个 n + 1个元素的数组,其中数组中的 k -th元素(0≤ k ≤ 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 ))。事实上,甚至可以很容易地修改它来处理预先不知道长度的输入流。
答案 2 :(得分:1)
我会想象按顺序将数组放入二叉树中。这样,您就可以跟踪哪个元素彼此相邻。然后只需简单地执行if(节点不直接相互链接)来对不相邻的节点求和。您可以使用递归来执行此操作并返回最大数量,使代码更容易。希望能帮助到你。
答案 3 :(得分:0)
对于包含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 */ }
}
...