Pre-processing code for RMQ Problem. What does it do? - algorithm

This is taken from TopCoder's Algorithm page - section on "Trivial algorithms for RMQ"
Supposedly a pre-processing function for calculating RMQ on the A array.
void process1(int M[MAXN][MAXN], int A[MAXN], int N)
{
int i, j;
for (i =0; i < N; i++)
M[i][i] = i;
for (i = 0; i < N; i++)
for (j = i + 1; j < N; j++)
if (A[M[i][j - 1]] < A[j])
M[i][j] = M[i][j - 1];
else
M[i][j] = j;
}
But I don't see how the M 2D array generated would be helpful in calculating the RMQ, what am I not getting?

Hint
The array A[] contains the sequence of elements that you calculate the RMQ for. The array M[][] contains answers for every query of type "What is the minimum element in range a..b?" into M[a][b].
Full answer
This way, you can look up the answer to any query on in constant time by looking at the respective element inside M[][].
The way it is calculated is as follows:
The first for-loop iterates over all elements and assigns the minimum of the range i..i to i. This is because the minimum of one-element-range is just that element.
The nested loops then calculate the RMQ answers for the other ranges i..k for all k > i. This is done by extending the already-calculated range that starts at i by one element at a time.

Related

How to change the spatial complexity of DP of binomial coefficient to O(n)?

This is the Dynamic Programming algorithm.
int bin2(int n, int k){
index i, j;
i tn B[0 ][0 k] B[0..n][0..k]; i
for(i=0; i <= n; i++)
for(j=0; j <= minimum(i,k); j++)
if (j 0 || j i) [i][j] 1
i
if (j==0 || j==i) B[i][j] = 1;
else B[i][j] = B[i-1][j-1] + B[i-1][j];
return B[n][k];
}
Its spatial complexity is O(n^2).
Can this be lowered to O(n)?
What should I do if I can use the property that 'when the calculation of a row is finished, the previously calculated value is not needed'?
In the code above, I got a hint that you can change k to 1 and j to j%2. What should I do?
The key is this line
B[i][j] = B[i-1][j-1] + B[i-1][j];
You see that, for the current state, we are dependent on i-1 and j-1. We don't need all of the previous rows, just the i-1th row.
Method 1
You should be looking to change it to something like
B[j] += B[j - 1];
Keep overwriting the same 1D array i.e iterating over j for each i.
Try solving it by yourself. If you still want to look at the solution, it is at the end of my answer.
Method 2
Some people like to keep two rows one for earlier and one for current one. They alternate between 0th row and 1st row by using mod. (i+1) % 2 will give 1 when i = 0 and 0 when i = 1. But this method uses two arrays instead of one as shown in method one.
Method 3
Similar to method 2. Some people keep two arrays previous and current. They swap the whole array instead of changing which array is the current one to fill. The swap happens after the j loop and inside the i loop. Refer the solution by #Maurycyt for this method.
Efficiency wise: Method 1 > Method 2 > Method 3
Solution with Method 1:
int binomialCoeff(int n, int k)
{
vector<int> dp(k+1, 0);
dp[0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = min(i, k); j > 0; j--)
dp[j] += dp[j-1];
}
return dp[k];
}
I am confused with your code, which seems to have several typos, but here is how you can evaluate {n \choose k} in linear spatial complexity, using the fact that {n \choose k} = (n!)/(k!*(n-k)!) is the k-th element of the n-th row of Pascal's triangle (which you seem to already know, I am just making sure it's out here).
int nchoosek(int n, int k)
{
int i, j; //These are indices of the row and column respectively
int oldrow [n+1], newrow [n+1]; //n+1 is the largest size of a row we will need.
//we will be computing a row of Pascal's triangle based on the previous row,
//then swapping the two.
for (i = 0; i <= n; i++) //we iterate over the rows
{
for (j = 0; j <= i; j++) //we iterate over the elements in a row, there are i+1 elements in row i, thus n+1 elements in row n.
{
if (j == 0 || j == i)
newrow[j] = 1; //we set the first and last element of a row to 1.
else
newrow[j] = oldrow[j-1] + oldrow[j]; //we set the other elements to the sum of the two elements above them in Pascal's triangle.
}
swap(oldrow, newrow); //we swap the two arrays, and will now be counting the next row, using the row which we just counted.
}
//the i-th row of Pascal's triangle will always end up in the oldrow array
return oldrow[k]; //we return its k-th element.
}

Algorithm for sorting an array using another array named gaps[]

This is a piece of code from a program. This code tends to sort the array
horses whose size is n. How does the array gap help in sorting the array horses?
int gaps[]={701,301,132,57,23,10,4,1};
for (k = 0; k < 8; k++)
for (i = gaps[k]; i < n; ++i)
{
temp = horses[i];
for (j = i; j >= gaps[k] && horses[j-gaps[k]] > temp; j -= gaps[k])
horses[j] = horses[j-gaps[k]];
horses[j] = temp;
}
gaps[] is an experimentally derived sequence for shell sort.
Take a look at the last entry in the wiki table for shell sort:
https://en.wikipedia.org/wiki/Shellsort#Gap_sequences
Wiki reference for this sequence:
https://oeis.org/A102549

Find the subarray within an array (containing at least TWO number) which has the largest sum

Find the subarray within an array (containing at least TWO number) which has the largest sum.
For example, given the array [-2,-1,-3,-4,-1],
the contiguous subarray [-2,-1] has the largest sum = -3.
try to do it in O(n) time
Followup, if input is stream, how to solve it
public int maxSubArray(int[] nums) {}
For an Array of size (N). Let us call it A
You can create another array B where you will store the sum so Far.
Now traverse through the parent Array.
int max = Integer.MIN;
B[0] = A[0];
for(i=1;i<A.length;i++)
{
if(A[i] > 0){
B[i]=B[i-1] + A[i];
}else if(A[i]+B[i-1] > max){
B[i] = A[i]+B[i-1]
max = A[i]+B[i-1]
}
else{
B[i] = A[i];
}
Now the max number in Array B has the max possible sum of the consecutive sub Array but you don't know the Sub Array.
You can use Kadane's Algorithm in modified fashion.
You can find Kadane' Algorithm here. (You will store the ends of the subarray too).
How can we modify it?
-> Just keep in track of the window size you are taking i.e. RIGHT-LEFT>=1
I think this should help for all set of numbers including negative.
Still for all negative numbers (which you can check in an O(n) go). Just loop FROM o to N : maximum = max(arr[i]+arr[i+1],maximum);
Just to ensure if the case gets covered.
Something like this should work:
int maxvalue = int.MIN_VALUE;
for (int i = 0; i < N; i++)
for (int j = i + 1; j < N; j++) {
int value = 0;
for (int x = i; x <= j; x++)
value += array[x];
if (value > maxvalue)
maxvalue = value;
}
return maxvalue;

Max sum in an array with constraints

I have this problem , where given an array of positive numbers i have to find the maximum sum of elements such that no two adjacent elements are picked. The maximum has to be less than a certain given K. I tried thinking on the lines of the similar problem without the k , but i have failed so far.I have the following dp-ish soln for the latter problem
int sum1,sum2 = 0;
int sum = sum1 = a[0];
for(int i=1; i<n; i++)
{
sum = max(sum2 + a[i], sum1);
sum2 = sum1;
sum1 = sum;
}
Could someone give me tips on how to proceed with my present problem??
The best I can think of off the top of my head is an O(n*K) dp:
int sums[n][K+1] = {{0}};
int i, j;
for(j = a[0]; j <= K; ++j) {
sums[0][j] = a[0];
}
if (a[1] > a[0]) {
for(j = a[0]; j < a[1]; ++j) {
sums[1][j] = a[0];
}
for(j = a[1]; j <= K; ++j) {
sums[1][j] = a[1];
}
} else {
for(j = a[1]; j < a[0]; ++j) {
sums[1][j] = a[1];
}
for(j = a[0]; j <= K; ++j) {
sums[1][j] = a[0];
}
}
for(i = 2; i < n; ++i) {
for(j = 0; j <= K && j < a[i]; ++j) {
sums[i][j] = max(sums[i-1][j],sums[i-2][j]);
}
for(j = a[i]; j <= K; ++j) {
sums[i][j] = max(sums[i-1][j],a[i] + sums[i-2][j-a[i]]);
}
}
sums[i][j] contains the maximal sum of non-adjacent elements of a[0..i] not exceeding j. The solution is then sums[n-1][K] at the end.
Make a copy (A2) of the original array (A1).
Find largest value in array (A2).
Extract all values before the it's preceeding neighbour and the values after it's next neighbour into a new array (A3).
Find largest value in the new array (A3).
Check if sum is larger that k. If sum passes the check you are done.
If not you will need to go back to the copied array (A2), remove the second larges value (found in step 3) and start over with step 3.
Once there are no combinations of numbers that can be used with the largest number (i.e. number found in step 1 + any other number in array is larger than k) you remove it from the original array (A1) and start over with step 0.
If for some reason there are no valid combinations (e.g. array is only three numbers or no combination of numbers are lower than k) then throw an exception or you return null if that seems more appropriate.
First idea: Brute force
Iterate all legal combination of indexes and build the sum on the fly.
Stop with one sequence when you get over K.
keep the sequence until you find a larger one, that is still smaller then K
Second idea: maybe one can force this into a divide and conquer thing ...
Here is a solution to the problem without the "k" constraint which you set out to do as the first step: https://stackoverflow.com/a/13022021/1110808
The above solution can in my view be easily extended to have the k constraint by simply amending the if condition in the following for loop to include the constraint: possibleMax < k
// 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;
}
*/
if (possibleMax > maxSum && possibleMax < k) {
maxSum = possibleMax;
}
}
As posted in the original link, this approach can be improved by adding memorization so that solutions to repeating sub problems are not recomputed. Or can be improved by using a bottom up dynamic programming approach (current approach is a recursive top down approach)
You can refer to a bottom up approach here: https://stackoverflow.com/a/4487594/1110808

Are these 2 knapsack algorithms the same? (Do they always output the same thing)

In my code, assuming C is the capacity, N is the amount of items, w[j] is the weight of item j, and v[j] is the value of item j, does it do the same thing as the 0-1 knapsack algorithm? I've been trying my code on some data sets, and it seems to be the case. The reason I'm wondering this is because the 0-1 knapsack algorithm we've been taught is 2-dimensional, whereas this is 1-dimensional:
for (int j = 0; j < N; j++) {
if (C-w[j] < 0) continue;
for (int i = C-w[j]; i >= 0; --i) { //loop backwards to prevent double counting
dp[i + w[j]] = max(dp[i + w[j]], dp[i] + v[j]); //looping fwd is for the unbounded problem
}
}
printf( "max value without double counting (loop backwards) %d\n", dp[C]);
Here is my implementation of the 0-1 knapsack algorithm: (with the same variables)
for (int i = 0; i < N; i++) {
for (int j = 0; j <= C; j++) {
if (j - w[i] < 0) dp2[i][j] = i==0?0:dp2[i-1][j];
else dp2[i][j] = max(i==0?0:dp2[i-1][j], dp2[i-1][j-w[i]] + v[i]);
}
}
printf("0-1 knapsack: %d\n", dp2[N-1][C]);
Yes, your algorithm gets you the same result. This enhancement to the classic 0-1 Knapsack is reasonably popular: Wikipedia explains it as follows:
Additionally, if we use only a 1-dimensional array m[w] to store the current optimal values and pass over this array i + 1 times, rewriting from m[W] to m[1] every time, we get the same result for only O(W) space.
Note that they specifically mention your backward loop.

Resources