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

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.

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 which only contains 0 and 1, and each row of the matrix is sorted, please find which row contains the most 1s

Given a matrix which only contains 0 and 1, and each row of the matrix is sorted, please find which row contains the most 1s. For a M*N matrix, O(M+N) time complexity is required, and O(1) space complexity is required.
Example
Input:
000000011111
000011111111
000000111111
000000000111
000000011111
000011111111
Output:
As row 2 and row 6 both contain 8 1s, the output is [2,8],[6,8].
I came up a solution:
public List<List<Integer>> mostOnes(int[][] a) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
for (int j = 0; j < a[0].length; j++) {
for (int i = 0; i < a.length; i++) {
if (a[i][j] == 1) {
List<Integer> res = new ArrayList<>();
res.add(i + 1);
res.add(a[0].length - j);
result.add(res);
}
}
if (result.size() != 0) break;
}
return result;
}
However, it is not O(M+N). Does anyone have other solutions?
The solution goes as follows:
Q= 0
For every row,
Search the next Q backward, starting from N - Q
Set the new Q there.
This process stops with Q indicating the largest number of 1's.
As the searches are performed by decreasing indexes from N down to 0 (at worst), and this is split between the M rows, the complexity is O(N + M). The trick is to continue the search from one row to the next staying in the current column rather than restarting from the edge.
Q= 0
for j in range(M):
for i in range(Q):
if A[j][N - 1 - i] == '0':
break
(Not guaranteed to be exact in details, but the working principle is there.)
0000000|11111
0000|11111111
0000|00111111
0000|00000111
0000|00011111
0000|11111111
Please check my O(m + n) implementation. The code is written in C, but easily you can convert it to Java.
int FindRow(vector<vector<int>>& mat) {
int m = mat.size(), n = mat[0].size();
int i = 0, j = n - 1, mx = 0;
while (i < m && j >= 0) {
while (j >= 0 && mat[i][j] == 1) --j;
mx = max(mx, n - j - 1);
++i;
}
return mx;
}
I have started with first row and last column. When I get first 0, I move to next row. We should check only remaining columns at most.

Sort a given array whose elements range from 1 to n , in which one element is missing and one is repeated

I have to sort this array in O(n) time and O(1) space.
I know how to sort an array in O(n) but that doesn't work with missing and repeated numbers. If I find the repeated and missing numbers first (It can be done in O(n)) and then sort , that seems costly.
static void sort(int[] arr)
{
for(int i=0;i<arr.length;i++)
{
if(i>=arr.length)
break;
if(arr[i]-1 == i)
continue;
else
{
while(arr[i]-1 != i)
{
int temp = arr[arr[i]-1];
arr[arr[i]-1] = arr[i];
arr[i] = temp;
}
}
}
}
First, you need to find missing and repeated numbers. You do this by solving following system of equations:
Left sums are computed simultaneously by making one pass over array. Right sums are even simpler -- you may use formulas for arithmetic progression to avoid looping. So, now you have system of two equations with two unknowns: missing number m and repeated number r. Solve it.
Next, you "sort" array by filling it with numbers 1 to n left to right, omitting m and duplicating r. Thus, overall algorithm requires only two passes over array.
void sort() {
for (int i = 1; i <= N; ++i) {
while (a[i] != a[a[i]]) {
std::swap(a[i], a[a[i]]);
}
}
for (int i = 1; i <= N; ++i) {
if (a[i] == i) continue;
for (int j = a[i] - 1; j >= i; --j) a[j] = j + 1;
for (int j = a[i] + 1; j <= i; ++j) a[j] = j - 1;
break;
}
}
Explanation:
Let's denote m the missing number and d the duplicated number
Please note in the while loop, the break condition is a[i] != a[a[i]] which covers both a[i] == i and a[i] is a duplicate.
After the first for, every non-duplicate number i is encountered 1-2 time and moved into the i-th position of the array at most 1 time.
The first-found number d is moved to d-th position, at most 1 time
The second d is moved around at most N-1 times and ends up in m-th position because every other i-th slot is occupied by number i
The second outer for locate the first i where a[i] != i. The only i satisfies that is i = m
The 2 inner fors handle 2 cases where m < d and m > d respectively
Full implementation at http://ideone.com/VDuLka
After
int temp = arr[arr[i]-1];
add a check for duplicate in the loop:
if((temp-1) == i){ // found duplicate
...
} else {
arr[arr[i]-1] = arr[i];
arr[i] = temp;
}
See if you can figure out the rest of the code.

Dynamic Programming: Find the rectangle in a grid that has the largest sum

I came across the following Dynamic Programming problem.
You have a grid of integers (so including negative numbers). Find the rectangle that has the largest sum of numbers.
Any idea how to do it for a whole matrix?
I solved it for a single array, so I pretty much followed what longest increasing subsequnce does, but only for contiguous numbers.
def array_largest_block(sequence)
len = sequence.size
parents = [nil]*len
my_largest = sequence
largest = sequence.max
for index in (1...len)
if my_largest[index] < my_largest[index] + my_largest[index - 1]
my_largest[index] = my_largest[index] + my_largest[index - 1]
parents[index] = index - 1
largest = [largest, my_largest[index]].max
end
end
end_index_of_largest_block = my_largest.find_index(largest)
i = end_index_of_largest_block
res = []
res << sequence[i]
while !parents[i].nil?
i = parents[i]
res << sequence[i]
end
return {l_sum: largest, start: i, end: end_index_of_largest_block}
end
So My thinking is,
find the sum of each square in the matrix (just 1x1 squares)
save the max for a possible answer
Run the same thing starting from smallest possible rectangle and calculate all of them until you find the max. Which is the DB part.
Any ideas? Or if you guys don't knwo the exact solution, which DP type algorithm should i look at?
This can be done in O(N^3), where N is the size of the matrix.
You basically choose the left and right column of the rectangle and then scan through the rows in linear time(using precomputed sums).
int totalBestSum = -10000000;
for (int leftCol = 1; leftCol <= N; leftCol++)
for (int rightCol = leftCol; rightCol <= N; rightCol++)
{
int curSum = 0, curBestSum = -10000000;
for (int row = 1; row <= N; row++) {
int rowSum = sumBetween(leftCol, rightCol, row);
curSum += rowSum;
if (curSum > curBestSum) curBestSum = curSum;
if (curSum < 0) curSum = 0;
}
if (curBestSum > totalBestSum) totalBestSum = curBestSum;
}
sumBetween is a function returning the sum of the numbers on a particular row between two columns. It can be implemented in constant time, using precomputed sums.
int sumBetween(int leftCol, int rightCol, int row)
{
return sum[row][rightCol] - sum[row][leftCol - 1];
}
To compute the sum array:
for (int row = 1; row <= N; row++)
for (int col = 1; col <= N; col++)
sum[row][col] = sum[row][col - 1] + matrix[row][col];
Seems like a duplicate, but still, look here: Getting the submatrix with maximum sum?
It is possible to do in O(N^3).
And why on earth do you use the 'NP-complete' tags?:D

Resources