Maximum sum such that no two elements are adjacent - arrays

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
Calculate the odd positioned element sum in the array
Calculate the even positioned element sum
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?

It's a case of dynamic programming. The algorithm is:
Do not take (sum up) any non-positive items
For positive numbers, split the problem in two: try taking and skiping the item and return the maximum of these choices:
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

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;
}

Related

Algorithm not functioning for sort squared array based off of input

I'm working on building an algorithm that sorts in place for an array of nondecreasing integers, and it's not passing some of my tests. I was wondering why? I've included a sample input and output as well.
import java.util.*;
class Program {
public int[] sortedSquaredArray(int[] array) {
int[] res = new int[array.length];
int leftPointer = 0;
int rightPointer = array.length - 1;
int counter = 0;
while (counter < array.length) {
int leftSquared = array[leftPointer] * array[leftPointer];
int rightSquared = array[rightPointer] * array[rightPointer];
if (leftSquared < rightSquared) {
res[counter] = leftSquared;
leftPointer++;
} else if (rightSquared <= leftSquared) {
res[counter] = rightSquared;
rightPointer--;
}
counter++;
}
return res;
}
}
"array": [-50, -13, -2, -1, 0, 0, 1, 1, 2, 3, 19, 20]
expected output:
[0, 0, 1, 1, 1, 4, 4, 9, 169, 361, 400, 2500]
what I'm getting:
[400, 361, 9, 4, 1, 1, 0, 0, 1, 4, 169, 2500]
If the array was specified to be in increasing order, your attempt was very close:
Just fill the result from larger squares to lower.
(If the array starts with a non-negative value, just return (a copy of) the input array.)
Just as #greybeard wrote: your mistake is to fill from the lower end, but you do not know the lowest square yet, since you are checking the two numbers with the BIGGEST square value.
This function should do what you want:
public int[] sortedSquaredArray(int[] array)
{
if (array.length == 0 || array[0] >= 0)
return array;
int[] res = new int[array.length];
int leftPointer = 0;
int leftSquared = array[leftPointer] * array[leftPointer];
int rightPointer = array.length - 1;
int rightSquared = array[rightPointer] * array[rightPointer];
int counter = rightPointer;
while (counter >= 0)
{
if (leftSquared >= rightSquared)
{
res[counter] = leftSquared;
leftPointer++;
leftSquared = array[leftPointer] * array[leftPointer];
}
else
{
res[counter] = rightSquared;
rightPointer--;
rightSquared = array[rightPointer] * array[rightPointer];
}
counter--;
}
return res;
}
Note the optimisations in line 3 and 4 and calculating the squared values only when needed. Also this function is NOT doing in-place sorting! It is returning a new array with the sorted squares. Doing an in-place sorting could be accomplished by re-assigning the values from the sorted array to the passed-in array before returning or using the passed-in array directly but having to move around the array-values a lot, if the left pointer is pointing to the bigger value.
You can watch the code in action with your example data here.

Smallest subarray with sum equal to k

I want to find the length smallest subarray whose sum is equal to k.
Input: arr[] = {2, 4, 6, 10, 2, 1}, K = 12
Output: 2
Explanation:
All possible subarrays with sum 12 are {2, 4, 6} and {10, 2}.
Input: arr[] = { 1, 2, 4, 3, 2, 4, 1 }, K = 7
Output: 2
Here's a solution using JavaScript.
It could be made more efficient, for sure, but I've coded it to work.
function lengthOfShortestSubArrayOfSumK(array, k) {
var combos=[];
for(var i=0; i<Math.pow(2, array.length); i++) {
var bin=("0".repeat(array.length)+i.toString(2)).slice(-array.length).split("");
var ones=bin.reduce((count, digit)=>{count+=digit=="1";return count;},0);
var sum=bin.reduce((sum, digit, index)=>{sum+=digit=="1"?array[index]:0;return sum;},0);
combos.push([bin, ones, sum]);
};
return combos.filter(combo=>combo[2]==k).sort((a, b)=>a[1]-b[1])[0][1];
}
var arraysAndKs=[
{array:[2, 4, 6, 10, 2, 1], k:12},
{array:[1, 2, 4, 3, 2, 4, 1], k:7}
];
for(arrayAndK of arraysAndKs)
console.log("Length of shortest sub array of ["+arrayAndK.array.join(", ")+"] with sum "+arrayAndK.k+" is : "+lengthOfShortestSubArrayOfSumK(arrayAndK.array, arrayAndK.k));
The Binary number between 0 and array.length squared will give us a representation of included array items in the sum.
We count how many "ones" are in that Binary number.
We sum array items masked by those "one"s.
We save into combos array an array of the Binary number, "one"s count, and sum.
We filter combos for sum k, sort by count of "one"s, and retrun the first's "one"s count.
I'm sure this can be translated to any programming language.
You can use an algorithm that finds a subset in size K, and save another variable that stores the number of members that make up such a subarray.
The algorithm for finding a K subarray is:
initialize an array of size K, Each place (idx) indicates whether there is a subarray that amounts to idx (I used a dictionary)
Go over any number (i) in the array, and any sum (j) we can reach in the previous iteration now we can reach j + i.
If in the K place it is marked TRUE, then there is a subarray that amounts to K.
Here's the solution in Python
def foo(arr,k):
dynamic = {0:0}
for i in arr:
temp = {}
for j, l in dynamic.items():
if i + j <= k: # if not it's not interesting us
# choose the smallest subarray
temp[i+j] = min(l+1,dynamic.get(i+j,len(arr)))
dynamic.update(temp)
return dynamic.get(k,-1)
the complexity is O(N*K).
I assumed that the subarray refers to any possible combinations of original array.
Here is a Python code that solves the problem under the condition that the subset must be contiguous:
in O(N) complexity
def shortest_contiguous_subarray(arr,k):
if k in arr:
return 1
n = len(arr)
sub_length = float('inf')
sub = arr[(i:=0)]
j = 1
while j < n:
while sub < k and j < n:
sub += arr[j]
j += 1
while sub > k:
sub -= arr[i]
i += 1
if sub == k:
# print(arr[i:j],j-i)
sub_length = min(sub_length,j-i)
sub -= arr[i]
i += 1
return sub_length if sub_length <= n else -1
This answer works for any array of positive numbers, and can be modified to work with arrays that have zero or negative elements if an O(n) pre-processing pass is performed (1. find the minimum element m, m <= 0, 2. make the whole array positive by adding -m+1 to all elements, 3. solve for sum + n*(1-m))
function search(input, goal) {
let queue = [ { avail: input.slice(), used: [], sum: 0 } ]; // initial state
for (let qi = 0; qi < queue.length; qi ++) {
let s = queue[qi]; // like a pop, but without using O(n) shift
for (let i = 0; i < s.avail.length; i++) {
let e = s.avail[i];
if (s.sum + e > goal) continue; // dead end
if (s.sum + e == goal) return [...s.used, e]; // eureka!!
queue.push({ // keep digging
avail: [...s.avail.slice(0, i), ...s.avail.slice(i+1)],
used: [...s.used, e],
sum: s.sum + e
});
}
}
return undefined; // no subset of input adds up to goal
}
console.log(search([2, 4, 6, 10, 2, 1], 12))
This is a classic breadth-first-search that does a little bit of pruning when it detects that we are already over the target sum. It can be further optimized to avoid exploring the same branch several times (for example, [4,2] is equivalent to [2,4]) - but this would require extra memory to keep a set of "visited" states. Additionally, you could add heuristics to explore more promising branches first.
I have done this by using unordered_map in c++. Hope this helps .
`
/* smallest subarray of sum k*/
#include<bits/stdc++.h>
using namespace std;
int main()
{
vector <int> v = {2,4,6,10,2,12};
int k=12;
unordered_map<int,int>m;
int start=0,end=-1;
int len=0,mini=INT_MAX;
int currsum=0;
for(int i=0;i<v.size();i++){
currsum+=v[i];
if(currsum==k){
start=0,end=i;
len=end-start+1;
mini=min(mini,len);
}
if(v[i]==k){
mini=min(mini,1);
}
if(m.find(currsum-k)!=m.end()){
end=i;
start=m[(currsum-k)]+1;
len=end-start+1;
mini=min(mini,len);
}
m[currsum]=i;
}
cout<<mini;
return 0;
}`
class Solution
{
static int findSubArraySum(int arr[], int N, int k)
{
// code here
// i use prefix sum and hashmap approach
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0,1);
// this is bcoz when 1st element is valid one
int count=0;
int sum=0;
for(int i=0;i<N;i++){
sum += arr[i];
// prefix sum
if(map.containsKey(sum-k)){
count += map.get(sum-k);
}
map.put(sum, map.getOrDefault(sum,0)+1);
}
return count;
}
}
// this approach even for -ve numbers
// i came to dis solution by prefix sum approach
This version finds the entire optimal sub-array, not only its length. It's based on a recursion. It will test each number of the array against the optimal sub-array of the rest.
const bestSum = (targetSum, numbers) => {
var shortestCombination = null
for (var i = 0; i < numbers.length; i++) {
var current = numbers[i];
if (current == 0) {
continue
}
if (current == targetSum) {
return [current]
}
if (current > targetSum) {
continue;
}
// "remove" current from array
numbers[i] = 0;
// now the recursion:
var rest = bestSum(targetSum - current, numbers)
if (rest && (!shortestCombination || rest.length + 1 < shortestCombination.length)) {
shortestCombination = [current].concat(rest);
}
// restore current to array
numbers[i] = current
}
return shortestCombination
}
console.log(bestSum(7, [5, 3, 4, 7])) // Should be 7, not [3, 4]
This is my code in Python 3. I used the same idea of find the longest subarray with a sum equal to K. But in the below code for every prefix sum I am storing the recent index.
def smallestSubArraySumLength(a, n, k):
d=defaultdict(lambda:-1)
d[0]=-1
psum=0
maxl=float('inf')
for i in range(n):
psum+=a[I]
if psum-k in d:
maxl=min(maxl, i-d[psum-k])
d[psum]=i
return maxl

array index in heapsort

In reading in Chapter 14 of Jon Bentley's "Programming Pearls", 2nd Edition, I understand that heaps use a one-based array and the easiest approach in C is to declare x[n+1] and waste element x[0] (page 148).
On page 157, Jon listed the complete heapsort pseudo code:
for i = [2, n]
siftup(i)
for (i = n; i >= 2; i--)
swap(1, i)
siftdown(i - 1)
Here is an implementation in C. However, the array index starts with 0, instead of 1.
void heapSort(int numbers[], int array_size)
{
int i, temp;
// Qiang: shouldn't the stop-condition be i >= 1?
for (i = (array_size / 2)-1; i >= 0; i--)
siftDown(numbers, i, array_size);
for (i = array_size-1; i >= 1; i--)
{
// Qiang: shouldn't the swap be done with numbmers[1], instead of numbers[0]?
temp = numbers[0];
numbers[0] = numbers[i];
numbers[i] = temp;
siftDown(numbers, 0, i-1);
}
}
void siftDown(int numbers[], int root, int bottom)
{
int done, maxChild, temp;
done = 0;
while ((root*2 <= bottom) && (!done))
{
if (root*2 == bottom)
maxChild = root * 2;
else if (numbers[root * 2] > numbers[root * 2 + 1])
maxChild = root * 2;
else
maxChild = root * 2 + 1;
if (numbers[root] < numbers[maxChild])
{
temp = numbers[root];
numbers[root] = numbers[maxChild];
numbers[maxChild] = temp;
root = maxChild;
}
else
done = 1;
}
}
My worry is, if the array starts with index 0, then the following properties will not hold (as written on page 148 in Jon's book):
leftchild(i) = 2*i
rightchild(i) = 2*i+1
parent(i) = i/2
It looks to me that the properties here only hold when the i starts with 1.
What strikes me is that the analysis part in the implementation used an array starting with index 1, while the implementation part used an array starting with index 0 and didn't waste the first element.
Am I missing anything here?
Edited
With help from interjay, I realized the error contained in the original implementation, which could be shown with a testing input array of {66,4,23,4,78,6,44,11,22,1,99}.
Changed the original siftDown() function a little bit to adjust the relationship between the index of parent and those of its children:
void siftDown(int numbers[], int root, int bottom)
{
int done, maxChild, temp;
done = 0;
while ((root*2 + 1 <= bottom) && (!done))
{
if (root*2 + 1 == bottom ||
numbers[root * 2 + 1] > numbers[root * 2 + 2])
maxChild = root * 2 + 1;
else
maxChild = root * 2 + 2;
if (numbers[root] < numbers[maxChild])
{
temp = numbers[root];
numbers[root] = numbers[maxChild];
numbers[maxChild] = temp;
root = maxChild;
}
else
done = 1;
}
}
Credits go to interjay, :-)
Afterword:
It looks the same error doesn't appear in the implementations in wikibooks and algorithmist. Hooray!
The heap elements can be stored starting with index 0 or index 1, the decision on which to use is up to you.
If the root element is at index 1, the mathematical relations between parent and child indices are simple as you've shown above, and for that reason many books choose to teach it that way.
If the root is at index 0, you'd get these relations instead:
leftchild(i) = 2*i+1
rightchild(i) = 2*i+2
parent(i) = (i-1) / 2
It doesn't matter which one you pick as long as you are consistent.
The C code you've shown seems incorrect to me. It starts with array index 0, but uses the parent/child relations appropriate for starting with index 1.
A reusable implementation of heapsort would want to start at a root index of 0 so the user could use a normal (0 based) array with it. You wouldn't want to require the user to allocate an extra member and start the array at index 1 just so they can use your heapsort function. You do need to use the modified parent/child calculations that #interjay shows.
Replying to little old thread, thought my small contribution might helps future visitors.
Experts please validate and correct my logic if I missed any scenarios.
Considered Qiang Xu link and interjay zero based index logic.
And here is the C# code and tested with the below inputs.
//-----------------------------------------------------------------------------------------------------------------------------------------------
// Input Arrays :
int[] ErrCaseArry = new int[] { 66, 4, 23, 4, 78, 6, 44, 11, 22, 1, 99};
int[] GenCaseArry = new int[] { 30, 20, 40, 10, 90, 160, 140, 100, 80, 70 };
int[] NearlySortedArry = new int[] { 1, 2, 3, 4, 6, 5 };
int[] FewSortedArry1 = new int[] { 3, 2, 1, 4, 5, 6 };
int[] FewSortedArry2 = new int[] { 6, 2, 3, 1, 5, 4 };
int[] ReversedArry1 = new int[] { 6, 5, 4, 3, 2, 1 };
int[] FewDuplsArry2 = new int[] { 1, 3, 1, 2, 1, 3 };
int[] MoreDuplsArry3 = new int[] { 1, 1, 2, 2, 1, 2 };
//-----------------------------------------------------------------------------------------------------------------------------------------------
public void HeapSort(int[] listToSort)
{
int LastChildIndex = listToSort.Length -1;
int parentElementIndex = ((LastChildIndex - 1)/ 2);
//1. Use this loop to Construct Heap Array (Max/Min) by using Heapify function on every node.
while (parentElementIndex >= 0) // (N - 1) / 2 to 0
{
Heapify(listToSort, parentElementIndex, LastChildIndex); // (N - 1) / 2 & Lenght - 1
parentElementIndex--;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------
AppendArrayToResultString("Max Heap\t", listToSort);
//2. Heap sort algorithm takes largest element off the heap and places it at the end of an array.
// This phase continue until all the elements are placed in the array that are in sorted order.
int sortedElementIndex = listToSort.Length - 1;
//-----------------------------------------------------------------------------------------------------------------------------------------------
// In this loop get Largest Element to Zero'th postion and move to end. and reduce the loop count from Heapify Array. So that elements gets sorted from right.
while (sortedElementIndex >= 0) // (N - 1) to 1
{
// Swap the elements (root(maximum value)) of the heap with the last element of the heap
Swap(ref listToSort[0], ref listToSort[sortedElementIndex]);
// sortedElementIndex-- : Decrease the size of the heap by one so that the previous max value will stay in its proper placement
sortedElementIndex--;
if (sortedElementIndex == -1) break;
// Since largest elemented from 0 to last, Re Heapify and get the remaining largest element and place it in 0 position.
Heapify(listToSort, 0, (sortedElementIndex)); // 0 to (N - 1)
}
//-----------------------------------------------------------------------------------------------------------------------------------------------
}
//Heapify() function maintain the heap property (Max Heap or Min Heap). Can be recursive or can use iteration loop like while/for.
void Heapify(int[] listToSort, int parentIndext, int lastChildIndext)
{
//bool doneFlag = false;
int largestElementIndex = 0;
int leftChildIndex = parentIndext * 2 + 1;
int rightChildIndex = parentIndext * 2 + 2;
while (leftChildIndex <= lastChildIndext) //&& !doneFlag)
{
// If leftChild is larger than rightChild or it is the last child and there is no rightChild for this parent.
// Then consider leftChild as largestElement else consider rightChild as largestElement.
if (leftChildIndex == lastChildIndext || listToSort[leftChildIndex] > listToSort[rightChildIndex])
{
largestElementIndex = leftChildIndex;
}
else
{
largestElementIndex = rightChildIndex;
}
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// If largestElement is larger than parent then swap them and make parent as largestElement to continue the loop.
if (listToSort[parentIndext] < listToSort[largestElementIndex])
{
// Make largestElement as parent. And continue finding if childs (left and right) are bigger than element in largestIndex position.
Swap(ref listToSort[parentIndext], ref listToSort[largestElementIndex]);
// Repeat to continue sifting down the child now
parentIndext = largestElementIndex;
leftChildIndex = ((parentIndext * 2) + 1);
rightChildIndex = ((parentIndext * 2) + 2);
}
else
{
//doneFlag = true;
break; // Trying to avoid extra flag condition check. Or return.
}
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------------
void Swap(ref int num1, ref int num2)
{
int temp = num1;
num1 = num2;
num2 = temp;
}

How to optimally divide an array into two subarrays so that sum of elements in both are same, otherwise give an error?

How to optimally divide an array into two subarrays so that sum of elements in both subarrays is same, otherwise give an error?
Example 1
Given the array
10, 20 , 30 , 5 , 40 , 50 , 40 , 15
It can be divided as
10, 20, 30, 5, 40
and
50, 40, 15
Each subarray sums up to 105.
Example 2
10, 20, 30, 5, 40, 50, 40, 10
The array cannot be divided into 2 arrays of an equal sum.
There exists a solution, which involves dynamic programming, that runs in O(n*TotalSum), where n is the number of elements in the array and TotalSum is their total sum.
The first part consists in calculating the set of all numbers that can be created by adding elements to the array.
For an array of size n, we will call this T(n),
T(n) = T(n-1) UNION { Array[n]+k | k is in T(n-1) }
(The proof of correctness is by induction, as in most cases of recursive functions.)
Also, remember for each cell in the dynamic matrix, the elements that were added in order to create it.
Simple complexity analysis will show that this is done in O(n*TotalSum).
After calculating T(n), search the set for an element exactly the size of TotalSum / 2.
If such an item exists, then the elements that created it, added together, equal TotalSum / 2, and the elements that were not part of its creation also equal TotalSum / 2 (TotalSum - TotalSum / 2 = TotalSum / 2).
This is a pseudo-polynomial solution. AFAIK, this problem is not known to be in P.
This is called partition problem. There are optimal solutions for some special cases. However, in general, it is an NP-complete problem.
In its common variant, this problem imposes 2 constraints and it can be done in an easier way.
If the partition can only be done somewhere along the length of the array (we do not consider elements out of order)
There are no negative numbers.
The algorithm that then works could be:
Have 2 variables, leftSum and rightSum
Start incrementing leftSum from the left, and rightSum from the right of the array.
Try to correct any imbalance in it.
The following code does the above:
public boolean canBalance(int[] nums) {
int leftSum = 0, rightSum = 0, i, j;
if(nums.length == 1)
return false;
for(i=0, j=nums.length-1; i<=j ;){
if(leftSum <= rightSum){
leftSum+=nums[i];
i++;
}else{
rightSum+=nums[j];
j--;
}
}
return (rightSum == leftSum);
}
The output:
canBalance({1, 1, 1, 2, 1}) → true OK
canBalance({2, 1, 1, 2, 1}) → false OK
canBalance({10, 10}) → true OK
canBalance({1, 1, 1, 1, 4}) → true OK
canBalance({2, 1, 1, 1, 4}) → false OK
canBalance({2, 3, 4, 1, 2}) → false OK
canBalance({1, 2, 3, 1, 0, 2, 3}) → true OK
canBalance({1, 2, 3, 1, 0, 1, 3}) → false OK
canBalance({1}) → false OK
canBalance({1, 1, 1, 2, 1}) → true OK
Ofcourse, if the elements can be combined out-of-order, it does turn into the partition problem with all its complexity.
a=[int(g) for g in input().split()] #for taking the array as input in a
single line
leftsum=0
n=len(a)
for i in range(n):
leftsum+=a[i] #calculates the sum of first subarray
rightsum=0
for j in range(i+1):
rightsum+=a[j] #calculates the sum of other subarray
if leftsum==rightsum:
pos=i+1 #if the sum of subarrays are equal,
break set position where the condition
gets satisfied and exit the loop
else:
pos=-1 #if the sum of subarrays is not
equal, set position to -1
if pos=-1 or pos=n:
print('It is not possible.')
else: #printing the sub arrays`
for k in range(n):
if pos=k:
print('')
print(str(a[k]),end='')
This Problem says that if an array can have two subarrays with their sum of elements as same.
So a boolean value should be returned.
I have found an efficient algorithm :
Algo: Procedure
Step 1: Take an empty array as a container , sort the initial array and keep in the empty one.
Step 2: now take two dynamically allocatable arrays and take out highest and 2nd highest from the auxilliary array and keep it in the two subarrays respectively , and delete from the auxiliary array.
Step 3: Compare the sum of elements in the subarrays , the smaller sum one will have chance to fetch highest remaining element in the array and then delete from the container.
Step 4: Loop thru Step 3 until the container is empty.
Step 5: Compare the sum of two subarrays , if they are same return true else false.
// The complexity with this problem is that there may be many combinations possible but this algo has one unique way .
Tried a different solution . other than Wiki solutions (Partition Problem).
static void subSet(int array[]) {
System.out.println("Input elements :" + Arrays.toString(array));
int sum = 0;
for (int element : array) {
sum = sum + element;
}
if (sum % 2 == 1) {
System.out.println("Invalid Pair");
return;
}
Arrays.sort(array);
System.out.println("Sorted elements :" + Arrays.toString(array));
int subSum = sum / 2;
int[] subSet = new int[array.length];
int tmpSum = 0;
boolean isFastpath = true;
int lastStopIndex = 0;
for (int j = array.length - 1; j >= 0; j--) {
tmpSum = tmpSum + array[j];
if (tmpSum == subSum) { // if Match found
if (isFastpath) { // if no skip required and straight forward
// method
System.out.println("Found SubSets 0..." + (j - 1) + " and "
+ j + "..." + (array.length - 1));
} else {
subSet[j] = array[j];
array[j] = 0;
System.out.println("Found..");
System.out.println("Set 1" + Arrays.toString(subSet));
System.out.println("Set 2" + Arrays.toString(array));
}
return;
} else {
// Either the tmpSum greater than subSum or less .
// if less , just look for next item
if (tmpSum < subSum && ((subSum - tmpSum) >= array[0])) {
if (lastStopIndex > j && subSet[lastStopIndex] == 0) {
subSet[lastStopIndex] = array[lastStopIndex];
array[lastStopIndex] = 0;
}
lastStopIndex = j;
continue;
}
isFastpath = false;
if (subSet[lastStopIndex] == 0) {
subSet[lastStopIndex] = array[lastStopIndex];
array[lastStopIndex] = 0;
}
tmpSum = tmpSum - array[j];
}
}
}
I have tested. ( It works well with positive number greater than 0) please let me know if any one face issue.
This is a recursive solution to the problem, one non recursive solution could use a helper method to get the sum of indexes 0 to a current index in a for loop and another one could get the sum of all the elements from the same current index to the end, which works. Now if you wanted to get the elements into an array and compare the sum, first find the point (index) which marks the spilt where both side's sum are equal, then get a list and add the values before that index and another list to go after that index.
Here's mine (recursion), which only determines if there is a place to split the array so that the sum of the numbers on one side is equal to the sum of the numbers on the other side. Worry about indexOutOfBounds, which can easily happen in recursion, a slight mistake could prove fatal and yield a lot of exceptions and errors.
public boolean canBalance(int[] nums) {
return (nums.length <= 1) ? false : canBalanceRecur(nums, 0);
}
public boolean canBalanceRecur(int[] nums, int index){ //recursive version
if(index == nums.length - 1 && recurSumBeforeIndex(nums, 0, index)
!= sumAfterIndex(nums, index)){ //if we get here and its still bad
return false;
}
if(recurSumBeforeIndex(nums, 0, index + 1) == sumAfterIndex(nums, index + 1)){
return true;
}
return canBalanceRecur(nums, index + 1); //move the index up
}
public int recurSumBeforeIndex(int[] nums, int start, int index){
return (start == index - 1 && start < nums.length)
? nums[start]
: nums[start] + recurSumBeforeIndex(nums, start + 1, index);
}
public int sumAfterIndex(int[] nums, int startIndex){
return (startIndex == nums.length - 1)
? nums[nums.length - 1]
: nums[startIndex] + sumAfterIndex(nums, startIndex + 1);
}
Found solution here
package sort;
import java.util.ArrayList;
import java.util.List;
public class ArraySumSplit {
public static void main (String[] args) throws Exception {
int arr[] = {1 , 2 , 3 , 4 , 5 , 5, 1, 1, 3, 2, 1};
split(arr);
}
static void split(int[] array) throws Exception {
int sum = 0;
for(int n : array) sum += n;
if(sum % 2 == 1) throw new Exception(); //impossible to split evenly
List<Integer> firstPart = new ArrayList<Integer>();
List<Integer> secondPart = new ArrayList<Integer>();
if(!dfs(0, sum / 2, array, firstPart, secondPart)) throw new Exception(); // impossible to split evenly;
//firstPart and secondPart have the grouped elements, print or return them if necessary.
System.out.print(firstPart.toString());
int sum1 = 0;
for (Integer val : firstPart) {
sum1 += val;
}
System.out.println(" = " + sum1);
System.out.print(secondPart.toString());
int sum2 = 0;
for (Integer val : secondPart) {
sum2 += val;
}
System.out.println(" = " + sum2);
}
static boolean dfs(int i, int limit, int[] array, List<Integer> firstPart, List<Integer> secondPart) {
if( limit == 0) {
for(int j = i; j < array.length; j++) {
secondPart.add(array[j]);
}
return true;
}
if(limit < 0 || i == array.length) {
return false;
}
firstPart.add(array[i]);
if(dfs(i + 1, limit - array[i], array, firstPart, secondPart)) return true;
firstPart.remove(firstPart.size() - 1);
secondPart.add(array[i]);
if(dfs(i + 1, limit, array, firstPart, secondPart)) return true;
secondPart.remove(secondPart.size() - 1);
return false;
}
}
def listSegmentation(theList):
newList = [[],[]]
print(theList)
wt1 = 0
wt2 = 0
dWt = 0
for idx in range(len(theList)):
wt = theList[idx]
if (wt > (wt1 + wt2) and wt1 > 0 and wt2 > 0):
newList[0] = newList[0] + newList[1]
newList[1] = []
newList[1].append(wt)
wt1 += wt2
wt2 = wt
elif ((wt2 + wt) >= (wt1 + wt)):
wt1 += wt
newList[0].append(wt)
elif ((wt2 + wt) < (wt1 + wt)):
wt2 += wt
newList[1].append(wt)
#Balancing
if(wt1 > wt2):
wtDiff = sum(newList[0]) - sum(newList[1])
ls1 = list(filter(lambda x: x <= wtDiff, newList[0]))
ls2 = list(filter(lambda x: x <= (wtDiff/2) , newList[1]))
while len(ls1) > 0 or len(ls2) > 0:
if len(ls1) > 0:
elDif1 = max(ls1)
newList[0].remove(elDif1)
newList[1].append(elDif1)
if len(ls2) > 0:
elDif2 = max(ls2)
newList[0].append(elDif2)
newList[1].remove(elDif2)
wtDiff = sum(newList[0]) - sum(newList[1])
ls1 = list(filter(lambda x: x <= wtDiff, newList[0]))
ls2 = list(filter(lambda x: x <= (wtDiff/2) , newList[1]))
if(wt2 > wt1):
wtDiff = sum(newList[1]) - sum(newList[0])
ls2 = list(filter(lambda x: x <= wtDiff, newList[1]))
ls1 = list(filter(lambda x: x <= (wtDiff/2) , newList[0]))
while len(ls1) > 0 or len(ls2) > 0:
if len(ls1) > 0:
elDif1 = max(ls1)
newList[0].remove(elDif1)
newList[1].append(elDif1)
if len(ls2) > 0:
elDif2 = max(ls2)
newList[0].append(elDif2)
newList[1].remove(elDif2)
wtDiff = sum(newList[1]) - sum(newList[0])
ls2 = list(filter(lambda x: x <= wtDiff, newList[1]))
ls1 = list(filter(lambda x: x <= (wtDiff/2) , newList[0]))
print(ls1, ls2)
print(sum(newList[0]),sum(newList[1]))
return newList
#Test cases
lst1 = [4,9,8,3,11,6,13,7,2,25,28,60,19,196]
lst2 = [7,16,5,11,4,9,15,2,1,13]
lst3 = [8,17,14,9,3,5,19,11,4,6,2]
print(listSegmentation(lst1))
print(listSegmentation(lst2))
print(listSegmentation(lst3))
This Python3 function will split and balance a list of numbers to two separate lists equal in sum, if the sum is even.
Python3 solution:
def can_partition(a):
mylist1 = []
mylist2 = []
sum1 = 0
sum2 = 0
for items in a:
# Take total and divide by 2.
total = sum(a)
if total % 2 == 0:
half = total//2
else:
return("Exiting, sum has fractions, total %s half %s" % (total, total/2))
mylist1.append(items)
print('Total is %s and half is %s' %(total, total/2))
for i in a:
sum1 = sum(mylist1)
sum2 = sum(mylist2)
if sum2 < half:
mypop = mylist1.pop(0)
mylist2.append(mypop)
# Function to swtich numbers between the lists if sums are uneven.
def switchNumbers(list1, list2,switch_diff):
for val in list1:
if val == switch_diff:
val_index = list1.index(val)
new_pop = list1.pop(val_index)
list2.append(new_pop)
#Count so while do not get out of hand
count = len(a)
while count != 0:
sum1 = sum(mylist1)
sum2 = sum(mylist2)
if sum1 > sum2:
diff = sum1 -half
switchNumbers(mylist1, mylist2, diff)
count -= 1
elif sum2 > sum1:
diff = sum2 - half
switchNumbers(mylist2, mylist1, diff)
count -= 1
else:
if sum1 == sum2:
print('Values of half, sum1, sum2 are:',half, sum1,sum2)
break
count -= 1
return (mylist1, mylist2)
b = [ 2, 3, 4, 2, 3, 1, 2, 5, 4, 4, 2, 2, 3, 3, 2 ]
can_partition(b)
Output:
Total is 42 total, half is 21.0
Values of half, sum1 & sum2 are : 21 21 21
([4, 4, 2, 2, 3, 3, 2, 1], [2, 3, 4, 2, 3, 2, 5])
A non optimal solution in python,
from itertools import permutations
def get_splitted_array(a):
for perm in permutations(a):
l1 = len(perm)
for i in range(1, l1):
if sum(perm[0:i]) == sum(perm[i:l1]):
return perm[0:i], perm[i:l1]
>>> a = [6,1,3,8]
>>> get_splitted_array(a)
((6, 3), (1, 8))
>>> a = [5,9,20,1,5]
>>>
>>> get_splitted_array(a)
((5, 9, 1, 5), (20,))
>>>
Its O(n) time and O(n) space
def equal_subarr(arr):
n=len(arr)
post_sum = [0] * (n- 1) + [arr[-1]]
for i in range(n - 2, -1, -1):
post_sum[i] = arr[i] + post_sum[i + 1]
prefix_sum = [arr[0]] + [0] * (n - 1)
for i in range(1, n):
prefix_sum[i] = prefix_sum[i - 1] + arr[i]
for i in range(n - 1):
if prefix_sum[i] == post_sum[i + 1]:
return [arr[:i+1],arr[i+1:]]
return -1
arr=[10, 20 , 30 , 5 , 40 , 50 , 40 , 15]
print(equal_subarr(arr))
>>> [[10, 20, 30, 5, 40], [50, 40, 15]]
arr=[10, 20, 30, 5, 40, 50, 40, 10]
print(equal_subarr(arr))
>>> -1
First, if the elements are integers, check that the total is evenly divisible by two- if it isn't success isn't possible.
I would set up the problem as a binary tree, with level 0 deciding which set element 0 goes into, level 1 deciding which set element 1 goes into, etc. At any time if the sum of one set is half the total, you're done- success. At any time if the sum of one set is more than half the total, that sub-tree is a failure and you have to back up. At that point it is a tree traversal problem.
public class Problem1 {
public static void main(String[] args) throws IOException{
Scanner scanner=new Scanner(System.in);
ArrayList<Integer> array=new ArrayList<Integer>();
int cases;
System.out.println("Enter the test cases");
cases=scanner.nextInt();
for(int i=0;i<cases;i++){
int size;
size=scanner.nextInt();
System.out.println("Enter the Initial array size : ");
for(int j=0;j<size;j++){
System.out.println("Enter elements in the array");
int element;
element=scanner.nextInt();
array.add(element);
}
}
if(validate(array)){
System.out.println("Array can be Partitioned");}
else{
System.out.println("Error");}
}
public static boolean validate(ArrayList<Integer> array){
boolean flag=false;
Collections.sort(array);
System.out.println(array);
int index=array.size();
ArrayList<Integer> sub1=new ArrayList<Integer>();
ArrayList<Integer> sub2=new ArrayList<Integer>();
sub1.add(array.get(index-1));
array.remove(index-1);
index=array.size();
sub2.add(array.get(index-1));
array.remove(index-1);
while(!array.isEmpty()){
if(compareSum(sub1,sub2)){
index=array.size();
sub2.add(array.get(index-1));
array.remove(index-1);
}
else{
index=array.size();
sub1.add(array.get(index-1));
array.remove(index-1);
}
}
if(sumOfArray(sub1).equals(sumOfArray(sub2)))
flag=true;
else
flag=false;
return flag;
}
public static Integer sumOfArray(ArrayList<Integer> array){
Iterator<Integer> it=array.iterator();
Integer sum=0;
while(it.hasNext()){
sum +=it.next();
}
return sum;
}
public static boolean compareSum(ArrayList<Integer> sub1,ArrayList<Integer> sub2){
boolean flag=false;
int sum1=sumOfArray(sub1);
int sum2=sumOfArray(sub2);
if(sum1>sum2)
flag=true;
else
flag=false;
return flag;
}
}
// The Greedy approach //
I was asked this question in an interview, and I gave below simple solution, as I had NOT seen this problem in any websiteS earlier.
Lets say Array A = {45,10,10,10,10,5}
Then, the split will be at index = 1 (0-based index) so that we have two equal sum set {45} and {10,10,10,10,5}
int leftSum = A[0], rightSum = A[A.length - 1];
int currentLeftIndex = 0; currentRightIndex = A.length - 1
/*
Move the two index pointers towards mid of the array untill currentRightIndex != currentLeftIndex. Increase leftIndex if sum of left elements is still less than or equal to sum of elements in right of 'rightIndex'.At the end,check if leftSum == rightSum. If true, we got the index as currentLeftIndex+1(or simply currentRightIndex, as currentRightIndex will be equal to currentLeftIndex+1 in this case).
*/
while (currentLeftIndex < currentRightIndex)
{
if ( currentLeftIndex+1 != currentRightIndex && (leftSum + A[currentLeftIndex + 1) <=currentRightSum )
{
currentLeftIndex ++;
leftSum = leftSum + A[currentLeftIndex];
}
if ( currentRightIndex - 1 != currentLeftIndex && (rightSum + A[currentRightIndex - 1] <= currentLeftSum)
{
currentRightIndex --;
rightSum = rightSum + A[currentRightIndex];
}
}
if (CurrentLeftIndex == currentRightIndex - 1 && leftSum == rightSum)
PRINT("got split point at index "+currentRightIndex);
#Gal Subset-Sum problem is NP-Complete and has a O(n*TotalSum) pseudo-polynomial Dynamic Programming algorithm. But this problem is not NP-Complete. This is a special case and in fact this can be solved in linear time.
Here we are looking for an index where we can split the array into two parts with same sum.
Check following code.
Analysis: O(n), as the algorithm only iterates through the array and does not use TotalSum.
public class EqualSumSplit {
public static int solution( int[] A ) {
int[] B = new int[A.length];
int[] C = new int[A.length];
int sum = 0;
for (int i=0; i< A.length; i++) {
sum += A[i];
B[i] = sum;
// System.out.print(B[i]+" ");
}
// System.out.println();
sum = 0;
for (int i=A.length-1; i>=0; i--) {
sum += A[i];
C[i] = sum;
// System.out.print(C[i]+" ");
}
// System.out.println();
for (int i=0; i< A.length-1; i++) {
if (B[i] == C[i+1]) {
System.out.println(i+" "+B[i]);
return i;
}
}
return -1;
}
public static void main(String args[] ) {
int[] A = {-7, 1, 2, 3, -4, 3, 0};
int[] B = {10, 20 , 30 , 5 , 40 , 50 , 40 , 15};
solution(A);
solution(B);
}
}
Algorithm:
Step 1) Split the array into two
Step 2) If the sum is equal, split is complete
Step 3) Swap one element from array1 with array2, guided by the four rules:
IF the sum of elements in array1 is less than sum of elements in array2
Rule1:
Find a number in array1 that is smaller than a number in array2 in such a way that swapping of
these elements, do not increase the sum of array1 beyond the expected sum. If found, swap the
elements and return.
Rule2:
If Rule1 is not is not satisfied, Find a number in array1 that is bigger than a number in array2 in
such a way that the difference between any two numbers in array1 and array2 is not smaller than
the difference between these two numbers.
ELSE
Rule3:
Find a number in array1 that is bigger than a number in array2 in such a way that swapping these
elements, do not decrease the sum of array1 beyond the expected sum. If found, swap the elements and return.
Rule4:
If Rule3 is not is not satisfied, Find a number in array1 that is smaller than a number in array2 in
such a way that the difference between any two numbers in array1 and array2 is not smaller than
the difference between these two numbers.
Step 5) Go to Step2 until the swap results in an array with the same set of elements encountered already
Setp 6) If a repetition occurs, this array cannot be split into two halves with equal sum. The current set of arrays OR the set that was formed just before this repetition should be the best split of the array.
Note: The approach taken is to swap element from one array to another in such a way that the resultant sum is as close to the expected sum.
The java program is available at Java Code
Please try this and let me know if not working. Hope it will helps you.
static ArrayList<Integer> array = null;
public static void main(String[] args) throws IOException {
ArrayList<Integer> inputArray = getinputArray();
System.out.println("inputArray is " + inputArray);
Collections.sort(inputArray);
int totalSum = 0;
Iterator<Integer> inputArrayIterator = inputArray.iterator();
while (inputArrayIterator.hasNext()) {
totalSum = totalSum + inputArrayIterator.next();
}
if (totalSum % 2 != 0) {
System.out.println("Not Possible");
return;
}
int leftSum = inputArray.get(0);
int rightSum = inputArray.get(inputArray.size() - 1);
int currentLeftIndex = 0;
int currentRightIndex = inputArray.size() - 1;
while (leftSum <= (totalSum / 2)) {
if ((currentLeftIndex + 1 != currentRightIndex)
&& leftSum != (totalSum / 2)) {
currentLeftIndex++;
leftSum = leftSum + inputArray.get(currentLeftIndex);
} else
break;
}
if (leftSum == (totalSum / 2)) {
ArrayList<Integer> splitleft = new ArrayList<Integer>();
ArrayList<Integer> splitright = new ArrayList<Integer>();
for (int i = 0; i <= currentLeftIndex; i++) {
splitleft.add(inputArray.get(i));
}
for (int i = currentLeftIndex + 1; i < inputArray.size(); i++) {
splitright.add(inputArray.get(i));
}
System.out.println("splitleft is :" + splitleft);
System.out.println("splitright is :" + splitright);
}
else
System.out.println("Not possible");
}
public static ArrayList<Integer> getinputArray() {
Scanner scanner = new Scanner(System.in);
array = new ArrayList<Integer>();
int size;
System.out.println("Enter the Initial array size : ");
size = scanner.nextInt();
System.out.println("Enter elements in the array");
for (int j = 0; j < size; j++) {
int element;
element = scanner.nextInt();
array.add(element);
}
return array;
}
}
public boolean splitBetween(int[] x){
int sum=0;
int sum1=0;
if (x.length==1){
System.out.println("Not a valid value");
}
for (int i=0;i<x.length;i++){
sum=sum+x[i];
System.out.println(sum);
for (int j=i+1;j<x.length;j++){
sum1=sum1+x[j];
System.out.println("SUm1:"+sum1);
}
if(sum==sum1){
System.out.println("split possible");
System.out.println("Sum: " +sum +" Sum1:" + sum1);
return true;
}else{
System.out.println("Split not possible");
}
sum1=0;
}
return false;
}
package PACKAGE1;
import java.io.*;
import java.util.Arrays;
public class programToSplitAnArray {
public static void main(String args[]) throws NumberFormatException,
IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("enter the no. of elements to enter");
int n = Integer.parseInt(br.readLine());
int x[] = new int[n];
int half;
for (int i = 0; i < n; i++) {
x[i] = Integer.parseInt(br.readLine());
}
int sum = 0;
for (int i = 0; i < n; i++) {
sum = sum + x[i];
}
if (sum % 2 != 0) {
System.out.println("the sum is odd and cannot be divided");
System.out.println("The sum is " + sum);
}
else {
boolean div = false;
half = sum / 2;
int sum1 = 0;
for (int i = 0; i < n; i++) {
sum1 = sum1 + x[i];
if (sum1 == half) {
System.out.println("array can be divided");
div = true;
break;
}
}
if (div == true) {
int t = 0;
int[] array1 = new int[n];
int count = 0;
for (int i = 0; i < n; i++) {
t = t + x[i];
if (t <= half) {
array1[i] = x[i];
count++;
}
}
array1 = Arrays.copyOf(array1, count);
int array2[] = new int[n - count];
int k = 0;
for (int i = count; i < n; i++) {
array2[k] = x[i];
k++;
}
System.out.println("The first array is ");
for (int m : array1) {
System.out.println(m);
}
System.out.println("The second array is ");
for (int m : array2) {
System.out.println(m);
}
} else {
System.out.println("array cannot be divided");
}
}
}
}
A BAD greedy heuristic to solve this problem: try sorting the list from least to greatest, and split that list into two by having list1 = the odd elements, and list2 = the even elements.
very simple solution with recursion
public boolean splitArray(int[] nums){
return arrCheck(0, nums, 0);
}
public boolean arrCheck(int start, int[] nums, int tot){
if(start >= nums.length) return tot == 0;
if(arrCheck(start+1, nums, tot+nums[start])) return true;
if(arrCheck(start+1, nums, tot-nums[start])) return true;
return false;
}
https://github.com/ShubhamAgrahari/DRjj/blob/master/Subarray_Sum.java
package solution;
import java.util.Scanner;
public class Solution {
static int SplitPoint(int arr[], int n)
{
int leftSum = 0;
for (int i = 0 ; i < n ; i++)
leftSum += arr[i];
int rightSum = 0;
for (int i = n-1; i >= 0; i--)
{
rightSum += arr[i];
leftSum -= arr[i] ;
if (rightSum == leftSum)
return i ;
}
return -1;
}
static void output(int arr[], int n)
{
int s = SplitPoint(arr, n);
if (s == -1 || s == n )
{
System.out.println("Not Possible" );
return;
}
for (int i = 0; i < n; i++)
{
if(s == i)
System.out.println();
System.out.print(arr[i] + " ");
}
}
public static void main (String[] args) {
Scanner sc= new Scanner(System.in);
System.out.println("Enter Array Size");
int n = sc.nextInt();
int arr[]= new int[n];
for(int i=0;i<n;i++)
{
arr[i]=sc.nextInt();
}
output(arr, n);
} }

Maximum sum of non consecutive elements

Given an array of positive integers, what's the most efficient algorithm to find non-consecutive elements from this array which, when added together, produce the maximum sum?
Dynamic programming? Given an array A[0..n], let M(i) be the optimal solution using the elements with indices 0..i. Then M(-1) = 0 (used in the recurrence), M(0) = A[0], and M(i) = max(M(i - 1), M(i - 2) + A[i]) for i = 1, ..., n. M(n) is the solution we want. This is O(n). You can use another array to store which choice is made for each subproblem, and so recover the actual elements chosen.
Let A be the given array and Sum be another array such that Sum[i] represents the maximum sum of non-consecutive elements from arr[0]..arr[i].
We have:
Sum[0] = arr[0]
Sum[1] = max(Sum[0],arr[1])
Sum[2] = max(Sum[0]+arr[2],Sum[1])
...
Sum[i] = max(Sum[i-2]+arr[i],Sum[i-1]) when i>=2
If size is the number of elements in arr then sum[size-1] will be the answer.
One can code a simple recursive method in top down order as:
int sum(int *arr,int i) {
if(i==0) {
return arr[0];
}else if(i==1) {
return max(arr[0],arr[1]);
}
return max(sum(arr,i-2)+arr[i],sum(arr,i-1));
}
The above code is very inefficient as it makes exhaustive duplicate recursive calls. To avoid this we use memoization by using an auxiliary array called sum as:
int sum(int *arr,int size) {
int *sum = malloc(sizeof(int) * size);
int i;
for(i=0;i<size;i++) {
if(i==0) {
sum[0] = arr[0];
}else if(i==1) {
sum[1] = max(sum[0],arr[1]);
}else{
sum[i] = max(sum[i-2]+arr[i],sum[i-1]);
}
}
return sum[size-1];
}
Which is O(N) in both space and time.
O(N) in time and O(1) in space (DP) solution:
int dp[2] = {a[0], a[1]};
for(int i = 2; i < a.size(); i++)
{
int temp = dp[1];
dp[1] = dp[0] + a[i];
dp[0] = max(dp[0], temp);
}
int answer = max(dp[0], dp[1]);
/**
* Given an array of positive numbers, find the maximum sum of elements such
* that no two adjacent elements are picked
* Top down dynamic programming approach without memorisation.
* An alternate to the bottom up approach.
*/
public class MaxSumNonConsec {
public static int maxSum(int a[], int start, int end) {
int maxSum = 0;
// Trivial cases
if (start == end) {
return a[start];
} else if (start > end) {
return 0;
} else if (end - start == 1) {
return a[start] > a[end] ? a[start] : a[end];
} else if (start < 0) {
return 0;
} else if (end >= a.length) {
return 0;
}
// Subproblem solutions, DP
for (int i = start; i <= end; i++) {
int possibleMaxSub1 = maxSum(a, i + 2, end);
int possibleMaxSub2 = maxSum(a, start, i - 2);
int possibleMax = possibleMaxSub1 + possibleMaxSub2 + a[i];
if (possibleMax > maxSum) {
maxSum = possibleMax;
}
}
return maxSum;
}
public static void main(String args[]) {
int a[] = { 8, 6, 11, 10, 11, 10 };
System.out.println(maxSum(a, 0, a.length - 1));
}
}
The solution by #Ismail Badawi does not seem to work in the following case: Let us take the array: 8, 3, 1, 7 Then in this case, the algo returns max sum = 9 whereas it should be 15.
A solution to correct it is given an array A[0..n], let M(i) be the optimal solution using the elements with indices 0..i. Then M(0) = A[0], and M(i) = max(M(i - 1), M(i - 2) + A[i], M(i-3) + A[i]) for i = 3, ..., n. M(n) is the solution we want. This is O(n).
IIUC: say your array is 1,2,3,4,5 then 3+5 would be 'correct' and 4+5 not, this means you'll have to find the largest numbers and check if they are consecutive. So an algorithm would be to make use of a second array, for the number of elements you need to add which you fill by traversing the original array and finding the largest non-consecutive integers, then add this up.
For the above array I guess [1,3], [1,4], [1,5], [1,3,5], [2,4], [2,5], [3,5] would be valid non-consecutive integers to be summed, the max sum would be 9 in this case [1,3,5]. So, to adapt the above algorithm, I would suggest you step through the array using several temporary arrays to find all the non-consecutive integer lists, and then check which is the largest. Keep in mind that 'most elements' does not mean 'largest sum'.
Dynamic programming solution is the most elegant of all.
And it serves for any value of the distance between two numbers that should not be considered.
But for k= 1, which is for consecutive numbers constraint, I tried using backtracking.
There are different patterns to be compared for the maximum sum. Below is the list :
Number of patterns for 1 = 1
[1]
Number of patterns for 2 = 2
[1][2]
Number of patterns for 3 = 2
[1, 3][2]
Number of patterns for 4 = 3
[1, 3][1, 4][2, 4]
Number of patterns for 5 = 4
[1, 3, 5][1, 4][2, 4][2, 5]
Number of patterns for 6 = 5
[1, 3, 5][1, 3, 6][1, 4, 6][2, 4, 6][2, 5]
Number of patterns for 7 = 7
[1, 3, 5, 7][1, 3, 6][1, 4, 6][1, 4, 7][2, 4, 6][2, 4, 7][2, 5, 7]
Number of patterns for 8 = 9
[1, 3, 5, 7][1, 3, 5, 8][1, 3, 6, 8][1, 4, 6, 8][1, 4, 7][2, 4, 6, 8][2, 4, 7][2, 5, 7][2, 5, 8]
Number of patterns for 9 = 12
[1, 3, 5, 7, 9][1, 3, 5, 8][1, 3, 6, 8][1, 3, 6, 9][1, 4, 6, 8][1, 4, 6, 9][1, 4, 7, 9][2, 4, 6, 8][2, 4, 6, 9][2, 4, 7, 9][2, 5, 7, 9][2, 5, 8]
Following is the code in java:
public class MaxSeqRecursive {
private static int num = 5;
private static int[] inputArry = new int[] { 1,3,9,20,7 };
private static Object[] outArry;
private static int maxSum = 0;
public static void main(String[] args) {
List<Integer> output = new ArrayList<Integer>();
output.add(1);
convert(output, -1);
for (int i = 0; i < outArry.length; i++) {
System.out.print(outArry[i] + ":");
}
System.out.print(maxSum);
}
public static void convert( List<Integer> posArry, int prevValue) {
int currentValue = -1;
if (posArry.size() == 0) {
if (prevValue == 2) {
return;
} else {
posArry.add(2);
prevValue = -1;
}
}
currentValue = (int) posArry.get(posArry.size() - 1);
if (currentValue == num || currentValue == num - 1) {
updateMax(posArry);
prevValue = (int) posArry.get(posArry.size() - 1);
posArry.remove(posArry.size() - 1);
} else {
int returnIndx = getNext(posArry, prevValue);
if (returnIndx == -2)
return;
if (returnIndx == -1) {
prevValue = (int) posArry.get(posArry.size() - 1);
posArry.remove(posArry.size() - 1);
} else {
posArry.add(returnIndx);
prevValue = -1;
}
}
convert(posArry, prevValue);
}
public static int getNext( List<Integer> posArry, int prevValue) {
int currIndx = posArry.size();
int returnVal = -1;
int value = (int) posArry.get(currIndx - 1);
if (prevValue < num) {
if (prevValue == -1)
returnVal = value + 2;
else if (prevValue - value < 3)
returnVal = prevValue + 1;
else
returnVal = -1;
}
if (returnVal > num)
returnVal = -1;
return returnVal;
}
public static void updateMax(List posArry) {
int sum = 0;
for (int i = 0; i < posArry.size(); i++) {
sum = sum + inputArry[(Integer) posArry.get(i) - 1];
}
if (sum > maxSum) {
maxSum = sum;
outArry = posArry.toArray();
}
}
}
Time complexity: O( number of patterns to be compared)
Another Java Implementation ( runs in linear time )
public class MaxSum {
private static int ofNonConsecutiveElements (int... elements) {
int maxsofar,maxi2,maxi1;
maxi1 = maxsofar = elements[0];
maxi2 = 0;
for (int i = 1; i < elements.length; i++) {
maxsofar = Math.max(maxi2 + elements[i], maxi1);
maxi2 = maxi1;
maxi1 = maxsofar;
}
return maxsofar;
}
public static void main(String[] args) {
System.out.println(ofNonConsecutiveElements(6, 4, 2, 8, 1));
}
}
My solution is O(N) time and O(1) space.
private int largestSumNonConsecutive(int[] a) {
return largestSumNonConsecutive(a, a.length-1)[1];
}
private int[] largestSumNonConsecutive(int[] a, int end) { //returns array largest(end-1),largest(end)
if (end==0) return new int[]{0,a[0]};
int[] largest = largestSumNonConsecutive(a, end-1);
int tmp = largest[1];
largest[1] = Math.max(largest[0] + a[end], largest[1]);
largest[0] = tmp;
return largest;
}
int nonContigousSum(vector<int> a, int n) {
if (n < 0) {
return 0;
}
return std::max(nonContigousSum(a, n - 1), nonContigousSum(a, n - 2) + a[n]);
}
this is the recursive approach with the help of which we can solve this question
(OPTIMAL SUB-STRUCTURE HALLMARK OF DYNAMIC PROGRAMMING.
Here we are considering two cases, in first we exclude a[n] and in the second we include a[n] and return the max of those sub cases found.
We are basically finding all the subsets of the array and returning the length of the non-contiguous array with max sum.
Use tabulation or memoization for avoiding same sub-problems.
A penny from me.
public class Problem {
/**
* Solving by recursion, top down approach. Always try this recursion approach and then go with
* iteration. We have to add dp table to optimize the time complexity.
*/
public static int maxSumRecur(int arr[], int i) {
if(i < 0) return 0;
if(i == 0) return arr[0];
if(i == 1) return Math.max(arr[0], arr[1]);
int includeIthElement = arr[i] + maxSumRecur(arr, i-2);
int excludeIthElement = maxSumRecur(arr, i-1);
return Math.max(includeIthElement, excludeIthElement);
}
/**
* Solving by iteration. Bottom up approach.
*/
public static void maxSumIter(int arr[]) {
System.out.println(Arrays.toString(arr));
int dp[] = new int[arr.length];
dp[0] = arr[0];
dp[1] = Math.max(arr[0], arr[1]);
for(int i=2; i <= arr.length - 1; i++) {
dp[i] = Math.max(arr[i] + dp[i-2], dp[i-1]);
}
System.out.println("Max subsequence sum by Iteration " + dp[arr.length - 1] + "\n");
}
public static void maxSumRecurUtil(int arr[]) {
System.out.println(Arrays.toString(arr));
System.out.println("Max subsequence sum by Recursion " + maxSumRecur(arr, arr.length - 1) +
"\n");
}
public static void main(String[] args) {
maxSumRecurUtil(new int[]{5, 5, 10, 100, 10, 5});
maxSumRecurUtil(new int[]{20, 1, 2, 3});
maxSumIter(new int[]{5, 5, 10, 100, 10, 5});
maxSumIter(new int[]{20, 1, 2, 3});
}
}
Make a list of numbers that is the odd or even sums corresponding to each number so far; e.g. for input of [1,2,4,1,2,3,5,3,1,2,3,4,5,2] the odd-even sums would be [1,2,5,3,7,6,12,9,13,11,16,15,21,17]
Now walk the list backwards greedily summing but skipping those elements whose odd/even sum is less than that of next-to-be-considered element.
src = [1,2,4,1,2,3,5,3,1,2,3,4,5,2]
odd_even_sums = src[:2]
for i in xrange(2,len(src)):
odd_even_sums.append(src[i] + odd_even_sums[i-2])
best = []
for i in xrange(len(src)-1,-1,-1):
if i == 0:
best.append(i)
elif odd_even_sums[i-1] > odd_even_sums[i]:
pass
elif odd_even_sums[i-1] == odd_even_sums[i]:
raise Exception("an exercise for the reader")
else:
best.append(i)
best.reverse()
print "Best:",",".join("%s=%s"%(b,src[b]) for b in best)
print "Scores:",sum(odd_even_sums[b] for b in best)
Outputs:
Best: 0=1,1=2,2=4,4=2,6=5,8=1,10=3,12=5
Scores: 77
public static int findMaxSum(int[] a){
int sum0=0; //will hold the sum till i-2
int sum1=0;//will hold the sum till i-1
for(int k : a){
int x=Math.max(sum0+k, sum1);//max(sum till (i-2)+a[i], sum till (i-1))
sum0=sum1;
sum1=x;
}
return sum1;
}
Below is the crux of algorithm:
max(max sum till (i-2)+a[i], max sum till (i-1))
O(N) time complexity and O(1) space complexity.
A rather naive yet complete implementation.
Recursion equation is T(n) = n^2 + nT(n-3), which if I'm not wrong leads to exponential time. The (n-3) comes from the fact a number cannot add with itself/previous/next numbers.
The program reports the constituent list that makes up the sum (there are multiple, exponentially growing, of these lists, but it just picks one).
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class MaxSumNoAdjacent {
private static class Sum {
int sum;
List<Integer> constituents = new ArrayList<>();
Sum(int sum, List<Integer> constituents) {
this.sum = sum;
this.constituents = constituents;
}
#Override
public String toString() {
return "sum: " + sum + " " + constituents.toString();
}
}
public static Sum maxSum(int[] arr) {
List<Integer> input = new ArrayList<>();
for (int i : arr) {
if (i != Integer.MIN_VALUE) { //Integer.MIN_VALUE indicates unreachability
input.add(i);
}
}
if (input.size() == 0) {
return null;
}
if (input.size() == 1) {
List<Integer> constituents = new ArrayList<>();
constituents.add(input.get(0));
return new Sum(input.get(0), constituents);
}
if (input.size() == 2) {
int max = Math.max(input.get(0), input.get(1));
List<Integer> constituents = new ArrayList<>();
constituents.add(max);
return new Sum(max, constituents);
}
Map<Integer, int[]> numberAndItsReachability = new HashMap<>();
for (int i = 0; i < input.size(); i++) {
int[] neighbours = new int[input.size()];
if (i > 0) {
neighbours[i-1] = Integer.MIN_VALUE; //unreachable to previous
}
if (i < input.size()-1) {
neighbours[i+1] = Integer.MIN_VALUE; //unreachable to next
}
neighbours[i] = Integer.MIN_VALUE; //unreachable to itself
for (int j = 0; j < neighbours.length; j++) {
if (neighbours[j] == 0) {
neighbours[j] = input.get(j); //remember values of reachable neighbours
}
}
numberAndItsReachability.put(input.get(i), neighbours);
}
Sum maxSum = new Sum(Integer.MIN_VALUE, null);
for (Entry<Integer, int[]> pair : numberAndItsReachability.entrySet()) {
Sum sumMinusThisNumber = maxSum(pair.getValue()); //call recursively on its reachable neighbours
if (sumMinusThisNumber != null) {
int candidateSum = sumMinusThisNumber.sum + pair.getKey();
if (maxSum.sum < candidateSum) {
sumMinusThisNumber.constituents.add(pair.getKey());
maxSum = new Sum(candidateSum, sumMinusThisNumber.constituents);
}
}
}
return maxSum;
}
public static void main(String[] args) {
int[] arr1 = {3,2,5,10,7};
int[] arr2 = {3,2,7,10};
int[] arr3 = {5,5,10,40,50,35};
int[] arr4 = {4,4,4,4};
System.out.println(maxSum(arr1).toString());
System.out.println(maxSum(arr2).toString());
System.out.println(maxSum(arr3).toString());
System.out.println(maxSum(arr4).toString());
}
}
Here is a C# version for reference (you may refer to: http://dream-e-r.blogspot.com/2014/07/maximum-sum-of-non-adjacent-subsequence.html):
In-order to solve a problem using dynamic programming there should be a solution which has optimal substructure and overlapping sub problems properties. And the current problem has optimal substructure property.
Say, f(i) is defined as maximum subsequence sum of non adjacent elements for 'i' items, then
f( i) = 0 if i = 0
max (f(i-1), f(i-2) + a[i])
Below is the algorithm for the same (no
te it can solved without the encapsulating data in 'record' - i just preferred it this way) - which should illustrate the above idea:
int FindMaxNonAdjuscentSubsequentSum(int[] a)
{
a.ThrowIfNull("a");
if(a.Length == 0)
{
return 0;
}
Record r = new Record()
{
max_including_item = a[0],
max_excluding_item = 0
};
for (int i = 1; i < a.Length; i++)
{
var t = new Record();
//there will be only two cases
//1. if it includes the current item, max is maximum of non adjuscent sub
//sequence sum so far, excluding the last item
t.max_including_item = r.max_excluding_item + a[i];
//2. if it excludes current item, max is maximum of non adjuscent subsequence sum
t.max_excluding_item = r.Max;
r = t;
}
return r.Max;
}
Unit Tests
[TestMethod]
[TestCategory(Constants.DynamicProgramming)]
public void MaxNonAdjascentSubsequenceSum()
{
int[] a = new int[] { 3, 2, 5, 10, 7};
Assert.IsTrue(15 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 3, 2, 5, 10 };
Assert.IsTrue(13 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 5, 10, 40, 50, 35 };
Assert.IsTrue(80 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 1, -1, 6, -4, 2, 2 };
Assert.IsTrue(9 == this.FindMaxNonAdjuscentSubsequentSum(a));
a = new int[] { 1, 6, 10, 14, -5, -1, 2, -1, 3 };
Assert.IsTrue(25 == this.FindMaxNonAdjuscentSubsequentSum(a));
}
where
public static int Max(int a, int b)
{
return (a > b) ? a : b;
}
class Record
{
public int max_including_item = int.MinValue;
public int max_excluding_item = int.MinValue;
public int Max
{
get
{
return Max(max_including_item, max_excluding_item);
}
}
}
public static int maxSumNoAdj(int[] nums){
int[] dp = new int[nums.length];
dp[0] = Math.max(0, nums[0]); // for dp[0], select the greater value (0,num[0])
dp[1] = Math.max(nums[1], Math.max(0, dp[0]));
int maxSum = Math.max(dp[0], dp[1]);
for(int i = 2; i < nums.length; i++){
int ifSelectCurrent = Math.max(nums[i] + dp[i-2], dp[i-2]);// if select, there are two possible
int ifNotSelectCurrent = Math.max(dp[i-1], dp[i-2]); // if not select, there are two posible
dp[i] = Math.max(ifSelectCurrent, ifNotSelectCurrent); // choose the greater one
maxSum = Math.max(dp[i], maxSum); // update the result
}
return maxSum;
}
public static void main(String[] args) {
int[] nums = {-9, 2, 3, -7, 1, 1};
System.out.println(maxSumNoAdj(nums));
}

Resources