How to implement variable number of for loops? - algorithm

I have a multi-dimension array to traverse, but the dimension of this array is a variable, it could be 2 or 10 or even more, for example when dimension equals to 2, I have to traverse it like:
for (int i=0; i<size[0]; ++i)
for (int j=0; j<size[1]; ++j)
// do something for arr[i * size[1] + j];
and for 3-dimension arr:
for (int i=0; i<size[0]; ++i)
for (int j=0; j<size[1]; ++j)
for (int k=0; k<size[2]; ++k)
// do something for arr[i * size[1] * size[2] + j * size[2] + k];
How to implement it in a effective way that can handle variable dimension?

Following up on this conversation from the comments:
Alternatively, have an array of indices, and increment the bottom one and when it reaches the appropriate size, reset it to 0 and increment the next one (and so on). Probably maintain an index into the array so you don't recalculate the offset on each iteration.
Thx #PaulHankin , your solution seems like what I am looking for. By maintaining an array of indices, how to really implement it?
What you need is an array of indexes, and a set of sizes of each index, so you know when to roll over. And you need to know when you've exceeded the entire structure's last index.
In pseudocode, something like this:
numDimensions = 3 // the number of dimensions
totalSize := size[0] * size[1] * size[2] // etc, the size of the whole structure
arrayIndex := 0
// here we're assuming that size and dimensionalIndex are indexed the same way
// initialized to 0, least significant digit at index 0
dimensionalIndex := Array(numDimensions)
while (arrayIndex < totalSize)
//
// Access arr[arrayIndex]
// arrayIndex should be equal to
// dimensionalIndex[0] + dimensionalIndex[1] * size[0] + dimensionalIndex[2] * size[0] * size[1], etc
//
// Increment the array counter
arrayIndex++
// Increment the dimensional counters (which map to your i, j, k, etc)
dimensionalIndex[0] += 1
for (indexIndex = 0; indexIndex < numDimensions; indexIndex++):
// If one of the dimensions is exceeded, set it to 0 and increment the next one
if (dimensionIndex[indexIndex] >= size[indexIndex]) and (indexIndex < numDimensions-1):
dimensionIndex[indexIndex+1]++
dimensionIndex[indexIndex] = 0
end if
end for
end while

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

Thought process for arriving at dynamic programming solution of Coins change problem

I am learning dynamic programming and came across this famous coins change problem.
The reccurence relation to solve this problem is given by
countCoinsChangeRec(arr, sum - arr[i], i) + countCoinsChangeRec(arr, sum, i - 1);
The simplest way to optimize the problem is by storing the solutions of sub problem. So I maintained a Map for each value of (sum,i). There by not solving same problems again.
String key = sum + ":" + i;
Integer memoizedVal = results.get(key);
if (memoizedVal != null) {
return memoizedVal;
}
Next level of optimization is having a 2D table of n X sum where n is number of elements in the set.
It is easily understandable from reccurence relation that (arr, sum - arr[i], i) translates to DP[sum-arr[i]] in same row.(Because i is same)
And (arr, sum, i - 1) translates to DP[i-1] (Previous row in sum column).
Complete solution with 2D matrix shown below.
public static int countWaysDP2D(int[] arr, int sum) {
int[][] table = new int[arr.length][sum + 1];
table[0][0] = 1;
for (int i = 1; i <= sum; i++) {
table[0][i] = 0;
}
for (int j = 1; j < arr.length; j++) {
table[j][0] = 1;
}
for (int i = 1; i < arr.length; i++) {
for (int j = 1; j <= sum; j++) {
int sumWithI = j - arr[i-1] < 0 ? 0 : table[i][j - arr[i-1]];
int sumWithoutI = table[i - 1][j];
table[i][j] = sumWithI + sumWithoutI;
}
}
return table[arr.length - 1][sum];
}
But the soultion given here in method 2 uses just 1D array as shown below
public static int countWaysDP1D(int[] arr, int sum) {
int[] table = new int[sum + 1];
table[0] = 1;
for (int i = 0; i < arr.length; i++) {
for (int j = arr[i]; j <= sum; j++) {
table[j] += table[j - arr[i]];
}
}
return table[sum];
}
What is the logic behind using just 1D array? I tested with many input values and results were same as 2D array. How is 2D array solution converted to 1D array?
I mean where are all the initial conditions gone?(0th row and 0th column)
For jth for loop, why does it iterate from jth element in the array till sum incremented by 1? It is really hard to visualize all of that. Can somebody explain this transformation step by step?
From the recurrence relation countCoinsChangeRec(arr, sum - arr[i], i) + countCoinsChangeRec(arr, sum, i - 1);, it is obvious that you need 2D array/table of size len(arr) x (sum+1) to store the results. We shall fill the table sequentially from top left of the table to bottom right and our answer is the value of bottom right cell. You need two values to fill each cell of the table table[i, sum - arr[i]] and table[i - 1, sum].
Consider filling a row -- 0th cell has value 1 and all other cells have a value of 0 at the start. To update a cell we need to lookup table[i, sum - arr[i]] which is within the same row. For table[i - 1, sum], we need to lookup the previous row. We don't need any other rows. So actually we only need 2 rows of space and we can alternatively treat one of the rows as previous row and other as current row being filled.
Now consider using 2 x (sum+1) table with just 2 rows to solve the problem. Consider row 1 is the current row being filled and row 0 is previous row which was already filled. Say arr = [2, 3, 7]. So you fill the row 1 as follows.
table[1, 0] = table[0, 0]
table[1, 1] = table[0, 1]
table[1, 2] = table[0, 2]
table[1, 3] = table[1, 0] + table[0, 3]
table[1, 4] = table[1, 1] + table[0, 4]
table[1, 5] = table[1, 2] + table[0, 5]
...
After observing above equations, another way to calculate the row 1 is copying row 0 onto unfilled row 1 and then filling row 1 as follows
Copy row 0 onto row 1
table[1, 3] += table[1, 0]
table[1, 4] += table[1, 1]
table[1, 5] += table[1, 2]
Instead of copying row 0 onto unfilled row 1, we can re-use row 0 itself. So the final space efficient avatar of the algorithm is - take a single row of size (sum+1). Assign row[0] = 1 as base condition. There is no difference in how we fill 0th row or any other row because the only lookups we make now is within the same row as shown above.
// Pseudo code
create row of size (sum+1)
row[0] = 1 // base condition
fill rest of the row with zeros
for element in arr: /* for (int i = 0; i < arr.length; i++) */
from column j where j - element >= 0 to end of row /* int j = arr[i]; j <= sum; j++ */
row[j] += row[j-element]
return last element of row
TL;DR: Note that in your 2D recurrence, when computing entries of table[i], you're only using table[i][...] and table[i - 1][...]. This should give you a hint to only store the previous and the current row, and lead you to reduce the space to a 1D array.
First, consider a much simpler recurrence to find the Nth Fibonacci number, where we reduce O(N) space to O(1) space:
For the recurrence F(n) = F(n - 1) + F(n - 2)
F[0] = 0
F[1] = 1
for(int i = 2; i <= N; i++) {
F[i] = F[i - 1] + F[i - 2]
}
return F[N]
Here, we see that we're only using the last 2 values of the recurrence, and do not need the whole array to store all values.
F0 = 0
F1 = 1
Fn = 1
for(int i = 2; i <= N; i++) {
Fn = F0 + F1
F0 = F1
F1 = Fn
}
return Fn
We now apply a similar reduction to your problem, just in one higher dimension. Taking your 2D version, we modify it to only store 2 rows table[i - 1] (as tablePrev) and table[i] (as tableI) and keep them updated.
tablePrev = // Initialised to the 0th row
// All I did was replace table[i - 1][...] with tablePrev[...],
// and table[i][...] with tableI[...]
for (int i = 1; i < arr.length; i++) {
tableI = tablePrev
for (int j = 1; j <= sum; j++) {
int sumWithI = j - arr[i-1] < 0 ? 0 : tableI[j - arr[i-1]];
int sumWithoutI = tablePrev[j];
tableI[j] = sumWithI + sumWithoutI;
}
tablePrev = tableI
}
That's it. We've reduced the space to a 1-D array - but we're using two arrays. For this particular problem, it is now easy to see that (due to the nature of updates on tableI) you don't even need tablePrev, and can simply re-use tableI, arriving at the final 1D solution you provide in the question.
The solution with a 1 dimensional array is just reusing space that you keep in a separate row. This is possible, because those "older" rows are not used again.
Take for example this statement in your code:
int sumWithoutI = table[i - 1][j];
You can verify that this is the last time you will ever read that value. The next time you read a value from the table, it will either have a greater value for i, or -- if it is the same -- a greater value for j. So there is room for "collapsing" all rows together, and overwriting an array value with a new value that really belongs to the next i value (row).

Given a matrix, cell is call good cell if row divides column

Given a n*m matrix, a cell is called good cell if row number (i) divides column number (j)
Example :
2*3 matrix => cells are {1,1}, {1,2}, {1,3}, {2,1}, {2,2}, {2,3} from which good cells can be defined as {1,1}, {1,2}, {1,3}, {2,2}
So the output is 4
I have figure out the logic for this, row 1 has all cells as good cells, row 2 has m/2 good cells, row 3 has m/3 good cells. (I am using just the integer dividend)
m/1 + m/2 + m/3 + ........ + m/n;
For which my code looks like =>
long count=1;
long answer = 0;
while(count<=n){
answer=answer + m/count;
count++;
}
But this code is getting timed out when I am submitting my solution. Need help to find better approach for this.
PS: Coding challenge is already over.
Try this one,
for(int i = 0 ; i < n; i++)
{
for(int j = 0; j < m; j += i) // j += i will save unwanted loops
{
// rest of your logic
}
}
As the value of i gets higher and higher nested loop will become more efficient
edit
The below code will be more efficient & correct than above. Now nested loop starts with the value of i instead of 0
for(int i = 0 ; i < n; i++)
{
for(int j = i; j < m; j += i) //j = i & j += i will save unwanted loops
{
// rest of your logic
}
}
as noted by n pronouns m this post incorrect since it only considers the case n==m
You may have a look at the Dirichlet divisor problem
One attempt is the formula of Benoit Cloitre:
(below octave implem)
function s = sumit(n)
s = 0;
for i = 1:n
s += floor(n/i);
end
end
n = 1e6
expect = sumit(n)
%A006218
u = floor(sqrt(n));
res = 2*sum(floor(n./(1:u))) - u^2
Where you avoid summing quite some terms.

Give a pseudocode for an algorithm that, given a list of n integers from the set {0, 1,

Problem statement:
Give a pseudocode for an algorithm that, given a list of n integers from the set {0, 1, . . . , k−1},
preprocesses its input to extract and store information that makes it possible to answer any query asking
how many of the n integers fall in the range [a..b] (with a and b being input parameters to the query) in
O(1) time. Explain how your algorithm works.
The preprocessing time should be O(n + k) in the worst case. Provide an argument showing that your
preprocessing algorithm meets that bound.
My attempt:
Counting Sort Pseudo Code
function countingSort(array, min, max)
count: array of (max – min + 1) elements //max is highest number, min is lowest
initialize count with 0 //set count = 0
for each number in array do
count[number – min] := count[number-min] + 1 //element i – min element = pos.
//pos + 1
done
z:= 0
for i from min to max do
while(count[ i – min] >0) do
array[z] := i
z := z + 1
count[i – min] := count [i – min] – 1
done
done
Find Pseudo Code
find(a, b)
??
Time Complexity Analysis:
We find that the total time complexity of Counting Sort takes O(k) time to initialize the array, O(n) time to read in the numbers and increment the appropriate element of counts. Another O(k) to create the array z, and another O(n) to scan and read through the list of numbers for a toal runtime of O(n+k).
Question:
The only problem I am having is that I do not know how I will report back to the user the number of integers that lie in between the range they have chosen [a..b] in O(1) time.. The only way I can think of retrieving that information is by looping through my array of sorted integers and having a counter to increment each time we find a number such that some some element is >= a && some element is <= b. Also should I include the actual numbers they have inputted in my search or rather should I just count the numbers in between them? The problem with looping through the array and having a counter to count the numbers between [a..b] is that this requires a for loop and is O(n). Any help would be greatly appreciated
The answer was trivial, just didn't think about it. After I use counting sort it resorts my list so that all I have to do is take the difference of the range asked of from the user. So for example
find(a,b)
numberofIntegersBetweenAandB = count[b] - count[a]
Working C++ example. Since the goal here is psuedo code, there are no error checks.
int * GenerateSums(int a[], size_t n, int min, int max)
{
size_t k = max + 2 - min;
int *sums = new int[k];
for(size_t i = 0; i < k; i++) // clear sums
sums[i] = 0;
for(size_t i = 0; i < n; i++) // set number of instances
sums[1+a[i]-min]++;
for(size_t i = 1; i < k; i++) // convert to cumulative sums
sums[i] += sums[i-1];
return sums;
}
int CountInRange(int sums[], int a, int b)
{
return sums[b+1] - sums[a];
}
int main()
{
int a[] = {4,0,3,4,2,4,1,4,3,4,3,2,4,2,3,1};
int *sums = GenerateSums(a, sizeof(a)/sizeof(a[0]), 0, 4);
int cnt;
cnt = CountInRange(sums, 0, 0); // returns 1
cnt = CountInRange(sums, 3, 4); // returns 10
cnt = CountInRange(sums, 0, 4); // returns 16
delete[] sums;
return 0;
}

How to find minimum positive contiguous sub sequence in O(n) time?

We have this algorithm for finding maximum positive sub sequence in given sequence in O(n) time. Can anybody suggest similar algorithm for finding minimum positive contiguous sub sequence.
For example
If given sequence is 1,2,3,4,5 answer should be 1.
[5,-4,3,5,4] ->1 is the minimum positive sum of elements [5,-4].
There cannot be such algorithm. The lower bound for this problem is O(n log n). I'll prove it by reducing the element distinctness problem to it (actually to the non-negative variant of it).
Let's suppose we have an O(n) algorithm for this problem (the minimum non-negative subarray).
We want to find out if an array (e.g. A=[1, 2, -3, 4, 2]) has only distinct elements. To solve this problem, I could construct an array with the difference between consecutive elements (e.g. A'=[1, -5, 7, -2]) and run the O(n) algorithm we have. The original array only has distinct elements if and only if the minimum non-negative subarray is greater than 0.
If we had an O(n) algorithm to your problem, we would have an O(n) algorithm to element distinctness problem, which we know is not possible on a Turing machine.
We can have a O(n log n) algorithm as follow:
Assuming that we have an array prefix, which index i stores the sum of array A from 0 to i, so the sum of sub-array (i, j) is prefix[j] - prefix[i - 1].
Thus, in order to find the minimum positive sub-array ending at index j, so, we need to find the maximum element prefix[x], which less than prefix[j] and x < j. We can find that element in O(log n) time if we use a binary search tree.
Pseudo code:
int[]prefix = new int[A.length];
prefix[0] = A[0];
for(int i = 1; i < A.length; i++)
prefix[i] = A[i] + prefix[i - 1];
int result = MAX_VALUE;
BinarySearchTree tree;
for(int i = 0; i < A.length; i++){
if(A[i] > 0)
result = min(result, A[i];
int v = tree.getMaximumElementLessThan(prefix[i]);
result = min(result, prefix[i] - v);
tree.add(prefix[i]);
}
I believe there's a O(n) algorithm, see below.
Note: it has a scale factor that might make it less attractive in practical applications: it depends on the (input) values to be processed, see remarks in the code.
private int GetMinimumPositiveContiguousSubsequenc(List<Int32> values)
{
// Note: this method has no precautions against integer over/underflow, which may occur
// if large (abs) values are present in the input-list.
// There must be at least 1 item.
if (values == null || values.Count == 0)
throw new ArgumentException("There must be at least one item provided to this method.");
// 1. Scan once to:
// a) Get the mimumum positive element;
// b) Get the value of the MAX contiguous sequence
// c) Get the value of the MIN contiguous sequence - allowing negative values: the mirror of the MAX contiguous sequence.
// d) Pinpoint the (index of the) first negative value.
int minPositive = 0;
int maxSequence = 0;
int currentMaxSequence = 0;
int minSequence = 0;
int currentMinSequence = 0;
int indxFirstNegative = -1;
for (int k = 0; k < values.Count; k++)
{
int value = values[k];
if (value > 0)
if (minPositive == 0 || value < minPositive)
minPositive = value;
else if (indxFirstNegative == -1 && value < 0)
indxFirstNegative = k;
currentMaxSequence += value;
if (currentMaxSequence <= 0)
currentMaxSequence = 0;
else if (currentMaxSequence > maxSequence)
maxSequence = currentMaxSequence;
currentMinSequence += value;
if (currentMinSequence >= 0)
currentMinSequence = 0;
else if (currentMinSequence < minSequence)
minSequence = currentMinSequence;
}
// 2. We're done if (a) there are no negatives, or (b) the minPositive (single) value is 1 (or 0...).
if (minSequence == 0 || minPositive <= 1)
return minPositive;
// 3. Real work to do.
// The strategy is as follows, iterating over the input values:
// a) Keep track of the cumulative value of ALL items - the sequence that starts with the very first item.
// b) Register each such cumulative value as "existing" in a bool array 'initialSequence' as we go along.
// We know already the max/min contiguous sequence values, so we can properly size that array in advance.
// Since negative sequence values occur we'll have an offset to match the index in that bool array
// with the corresponding value of the initial sequence.
// c) For each next input value to process scan the "initialSequence" bool array to see whether relevant entries are TRUE.
// We don't need to go over the complete array, as we're only interested in entries that would produce a subsequence with
// a value that is positive and also smaller than best-so-far.
// (As we go along, the range to check will normally shrink as we get better and better results.
// Also: initially the range is already limited by the single-minimum-positive value that we have found.)
// Performance-wise this approach (which is O(n)) is suitable IFF the number of input values is large (or at least: not small) relative to
// the spread between maxSequence and minSeqence: the latter two define the size of the array in which we will do (partial) linear traversals.
// If this condition is not met it may be more efficient to replace the bool array by a (binary) search tree.
// (which will result in O(n logn) performance).
// Since we know the relevant parameters at this point, we may below have the two strategies both implemented and decide run-time
// which to choose.
// The current implementation has only the fixed bool array approach.
// Initialize a variable to keep track of the best result 'so far'; it will also be the return value.
int minPositiveSequence = minPositive;
// The bool array to keep track of which (total) cumulative values (always with the sequence starting at element #0) have occurred so far,
// and the 'offset' - see remark 3b above.
int offset = -minSequence;
bool[] initialSequence = new bool[maxSequence + offset + 1];
int valueCumulative = 0;
for (int k = 0; k < indxFirstNegative; k++)
{
int value = values[k];
valueCumulative += value;
initialSequence[offset + valueCumulative] = true;
}
for (int k = indxFirstNegative; k < values.Count; k++)
{
int value = values[k];
valueCumulative += value;
initialSequence[offset + valueCumulative] = true;
// Check whether the difference with any previous "cumulative" may improve the optimum-so-far.
// the index that, if the entry is TRUE, would yield the best possible result.
int indexHigh = valueCumulative + offset - 1;
// the last (lowest) index that, if the entry is TRUE, would still yield an improvement over what we have so far.
int indexLow = Math.Max(0, valueCumulative + offset - minPositiveSequence + 1);
for (int indx = indexHigh; indx >= indexLow; indx--)
{
if (initialSequence[indx])
{
minPositiveSequence = valueCumulative - indx + offset;
if (minPositiveSequence == 1)
return minPositiveSequence;
break;
}
}
}
return minPositiveSequence;
}
}

Resources