Maximum sum in array with special conditions - algorithm

Assume we have an array with n Elements ( n%3 = 0).In each step, a number is taken from the array. Either you take the leftmost or the rightmost one. If you choose the left one, this element is added to the sum and the two right numbers are removed and vice versa.
Example: A = [100,4,2,150,1,1], sum = 0.
take the leftmost element. A = [4,2,150] sum = 0+100 =100
2.take the rightmost element. A = [] sum = 100+150 = 250
So the result for A should be 250 and the sequence would be Left, Right.
How can I calculate the maximum sum I can get in an array? And how can I determine the sequence in which I have to extract the elements?
I guess this problem can best be solved with dynamic programming and the concrete sequence can then be determined by backtracking.

The underlying problem can be solved via dynamic programming as follows. The state space can be defined by letting
M(i,j) := maximum value attainable by chosing from the subarray of
A starting at index i and ending at index j
for any i, j in {1, N} where `N` is the number of elements
in the input.
where the recurrence relation is as follows.
M(i,j) = max { M(i+1, j-2) + A[i], M(i+2, j-1) + A[j] }
Here, the first value corresponds to the choice of adding the beginning of the array while the second value connesponds to the choice of subtracting the end of the array. The base cases are the states of value 0 where i=j.

Related

Find minimum number of steps to collect target number of coins

Given a list of n houses, each house has a certain number of coins in it. And a target value t. We have to find the minimum number of steps required to reach the target.
The person can choose to start at any house and then go right or left and collect coins in that direction until it reaches the target value. But the person cannot
change the direction.
Example: 5 1 2 3 4 These are supposed the coin values in 5 houses and the target is 13 then the minimum number of steps required is 5 because we have to select all the coins.
My Thoughts:
One way will be for each index i calculate the steps required in left or right direction to reach the target and then take the minimum of all these 2*n values.
Could there be a better way ?
First, let's simplify and canonize the problem.
Observation 1: The "choose direction" capability is redundant, if you choose to go from house j to house i, you can also go from i to j to have the same value, so it is sufficient to look at one direction only.
Observation 2: Now that we can look at the problem as going from left to right (observation 1), it is clear that we are looking for a subarray whose value exceeds k.
This means that we can canonize the problem:
Given an array with non negative values a, find minimal subarray
with values summing k or more.
There are various ways to solve this, one simple solution using a sorted map (balanced tree for example) is to go from left to right, summing values, and looking for the last element seen whose value was sum - k.
Pseudo code:
solve(array, k):
min_houses = inf
sum = 0
map = new TreeMap()
map.insert(0, -1) // this solves issue where first element is sufficient on its own.
for i from 0 to array.len():
sum = sum + array[i]
candidate = map.FindClosestLowerOrEqual(sum - k)
if candidate == null: // no matching sum, yet
continue
min_houses = min(min_houses, i - candidate)
map.insert(sum, i)
return min_houses
This solution runs in O(nlogn), as each map insertion takes O(logn), and there are n+1 of those.
An optimization, running in O(n), can be done if we take advantage of "non negative" trait of the array. This means, as we go on in the array - the candidate chosen (in the map seek) is always increasing.
We can utilize it to have two pointers running concurrently, and finding best matches, instead of searching from scratch in the index as we did before.
solve(array, k):
left = 0
sum = 0
min_houses = infinity
for right from 0 to len(array):
sum = sum + array[right]
while (left < right && sum >= k):
min_houses = min(min_houses, right - left)
sum = sum - array[left]
left = left + 1
return min_houses
This runs in O(n), as each index is increased at most n times, and every operation is O(1).

How to find a subset whose minimum distance between elements is greater than a certain value and whose sum of values of elements is maximized?

I'm trying to solve an algorithm problem here.
There are n distinct elements in an array, and their positions are from x_1 to x_n. Each element has an individual value of p (so for the i-th element in the array, its position would be x_i, and its p value would be p_i).
First you choose an arbitrary subset S of the given array (so 0 <= |S| <= n) such that the distance between any two elements is greater than k (so every {x_i,x_j} ⊆ S must have |xi−xj| > k). Then you have to find the maximum sum of p values of any pair of elements in such subset S.
Any ideas on how I could do this in polynomial time?
Thank you.
Dynamic programming
At every element, you have a choice to include it or not. If you include it you can't include any of the last k elements, current value + max value at current index - k. If you don't include the current element the last index max value will be the current element max value.
for(let i=0;i<x.length;++i)
DP[i] = Math.max(DP[i-k]+x[i],DP[i-1])

Sum of all numbers less than k in a range using segment tree

I have an array A with elements size <= 10^6.
I want to implement a data structure which gives me sum of all elements less thank k in a particular range say l to r.
I know it can be solved using segment tree but dont know how to maintain segment tree for variable k queries.
Please help me with pseudo code.
As there are no updates I think Mo's Algorithms could also be used.
Below assumes the elements in your array are all positive
how about not maintaining segment tree for specific k but resolving the query instead
Just consider your segment tree.
At each node Node_i, you know:
its covering sum: s_i
the number of elements it covers: n_i
So two steps:
For a given range query, get down to the corresponding node Node_i.
For that Node_i, s_i is the sum of its two children's sum. For each of those given child Node_j with its n_j elements covered: two possibilities
n_j*k < s_j :all elements are less than k
n_j*k >= s_j:at least one element is greater or equal than k
So first case, the child's sum is already valid, nothing more to do.
Second case, you have to explore the child and so forth until nothing more to do
At some point, (if you have an invalid element) you will reach a bottom of the tree: that very node (also an elem) is bad, and you backtrack that fact.
When you get back to your node Node_i, you substract from s_i all those bad leaf node's value you found.
pseudo code is:
#node is like:
#children:[c1, c2]
#n:number of elem covered
#sum: sum of all elemens it covers
#returns the sum of the covered elements whose value is __greater__ or equal than k
def explore(node, k):
#terminal case
if node.n == 1:
if node.sum >= k:
return node.sum
# when the range query is of size 1...,
# you may want to handle that elsewhere (e.g before calling explore)
return 0
end
#standard case
[c1,c2] = node.children
totalsum = 0
if c1.n * k < c1.sum
#all your elems are less than k, substract nothing
totalsum += 0
else
totalsum += explore(c1, k)
#same for c2...
return totalsum
If your k is fixed you can map array values as follows:
If element is less than k put that value in leaf, else put 0. Then you can use standard sum function because all elements that are greater than k will be 0 in leafs and won't affect sum.

Finding the sum of maximum difference possible from all subintervals of a given array

I have a problem designing an algorithm. The problem is that this should be executed in O(n) time.
Here is the assignment:
There is an unsorted array "a" with n numbers.
mij=min{ai, ai+1, ..., aj}, Mij=max{ai, ai+1, ..., aj}
Calculate:
S=SUM[i=1,n] { SUM[j=i,n] { (Mij - mij) } }
I am able to solve this in O(nlogn) time. This is a university research assignment. Everything that I tried suggests that this is not possible. I would be very thankful if you could point me in the right direction where to find the solution. Or at least prove that this is not possible.
Further explanation:
Given i and j, find the maximum and minimum elements of the array slice a[i:j]. Subtract those to get the range of the slice, a[max]-a[min].
Now, add up the ranges of all slices for all (i, j) such that 1 <= i <= j <= n. Do it in O(n) time.
This is pretty straight forward problem.
I will assume that it is array of objects (like pair of values or tuples) not numbers. First value is index in array and the second is value.
Right question here is how many time we need to multiply each number and add/subtract it from the sum ie in how many sub-sequences it is maximum and minimum element.
This problem is connected to finding next greatest element (nge), you can see here, just to know it for future problems.
I will write it in pseudo code.
subsum (A):
returnSum = 0
//i am pushing object into the stack. Firt value is index in array, secong is value
lastStackObject.push(-1, Integer.MAX_INT)
for (int i=1; i<n; i++)
next = stack.pop()
stack.push(next)
while (next.value < A[i].value)
last = stack.pop()
beforeLast = stack.peek()
retrunSum = returnSum + last.value*(i-last.index)*(last.index-beforeLast.index)
stack.push(A[i])
while stack is not empty:
last = stack.pop()
beforeLast = stack.peek()
retrunSum = returnSum + last.value*(A.length-last.index)*(last.index-beforeLast.index)
return returnSum
sum(A)
//first we calculate sum of maximum values in subarray, and then sum of minimum values. This is done by simply multiply each value in array by -1
retrun subsum(A)+subsum(-1 for x in A.value)
Time complexity of this code is O(n).
Peek function is just to read next value in stack without popping it.

Dynamic Programming a Count of Subsequences with Property?

Consider a dynamic programming problem that asks how many distinct subsequences (not necessarily contiguous) of a sequence S have a certain property P of value p0.
The range of P is small and finite, and there is an efficient way of calculating P:
P(s1 + s2) = f(P(s1), P(s2))
where + denotes sequence concatenation.
One way to do this would be to count how many subsequences there are of the prefix S[1] + S[2] + ... + S[k] of S that have property px. (Store this in Count[px][k])
So the recursion is:
Count[px][k] = Count[px][k-1] // not using element S[k];
P pq = f(px,P(S[k])); // calculate property pq of appending element S[k]
Count[pq][k] += Count[px][k-1] // add count of P(prefix+S[k])
and the answer is then:
return Count[p0][S.length]
This works when the elements of S are pairwise distinct, however it will count twice subsequences that have equal value but use different elements of different positions.
How can I modify this algorithm so that it counts equal subsequences exactly once ? (ie only counts distinct subsequences)
Suppose the sequence is of characters and S[k] is the letter x.
The problem is that you have double counted all sequences that don't use S[k], but nevertheless end with x (this can only happen if x happened earlier in the sequence).
Suppose the last time x appeared was at element S[j].
All the distinct sequences that end with x is simply given by counting all distinct sequences up to position j-1, and then adding x onto all of these.
We can therefore correct for the double counting by subtracting this count.
Count[px][k] = Count[px][k-1] // not using element S[k]
P pq = f(px,P(S[k])) // property pq of appending element S[k]
j = index of previous location in string where S[j]==S[k]
Count[pq][k] += Count[px][k-1] // using element S[k]
Count[pq][k] -= Count[px][j-1] // Removing double counts

Resources