Reputation: 257
Now the available solution every where is to have an include and exclude sum . At the end max
of these two will give me the output.
Now initially I was having difficulty to understand this algorithm and I thought why not going in a simple way.
Algo: Loop over the array by increasing array pointer two at a time
sum
in the arraysum
At the end, take max
of this two sum
.
in that way, I think complexity will be reduced to half O(n/2)
Is this algo correct?
Upvotes: 5
Views: 4818
Reputation: 11
dynamic programming inclusion exclusion approach is correct your algorithm would not work for test cases like 3 2 7 10 in this test case the two elements we take are 3 10 and sum is 13 instead of 3,7 or 2,10.may you understand what i am saying and for further clarity code is below
Java Implementation
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;
}
Upvotes: 0
Reputation: 186668
It's a case of dynamic programming. The algorithm is:
Let's show the 2nd step, imagine we are given:
[1, 2, 3, 4, 5, 6, 10, 125, -8, 9]
1
is positive, that's why
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# implementation (the simplest code in order to show the naked idea, no further optimization):
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);
}
Test:
Console.WriteLine(BestSum(new int[] { 1, -2, -3, 100 }));
Console.WriteLine(BestSum(new int[] { 100, 8, 10, 20, 7 }))
Outcome:
101
120
Please, check, that your initial algorithm returns 98
and 117
which are suboptimal sums.
Edit: In real life you may want to add some optimization, e.g. memoization and special cases tests:
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);
}
Test:
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}");
Outcome:
odd: 246117 even: 247137 suboptimal: 247137 actual: 290856
Upvotes: 3