Interview Question on Algorithms regarding Matrices - algorithm

You are provided with an N*M matrix containing Integer values. Your task is to select one integer from each row such that the sum of these integers is maximum. However, you are not allowed to select two integers from adjacent rows in the same column.
How can I do this problem in less than O(N^M) (or O(M^N))?

I came up with two possible solutions: 1. using recursion, 2. using DP.
1. Using Recursion
I think you already have this solution. I made a recursive function that goes through each row in matrix and calls recursion for each column. As you mentioned, the time complexity would be O(M^N) where N is the number of rows and M is the number of columns.
int getMaxSum(int[][] matrix) {
return getMax(matrix, 0, -1);
}
int getMax(int[][] matrix, int row, int prevCol) {
if (row >= matrix.length) return 0;
int result = Integer.MIN_VALUE;
for (int i = 0; i < matrix[row].length; i++) {
if (i == prevCol) continue;
int sum = getMax(matrix, row+1, i) + matrix[row][i];
result = Math.max(result, sum);
}
return result;
}
2. Using DP
Instead of recursively going through all rows and columns, I can use DP to keep track of maximum sum for each column up to a certain row. For example, DP[r][c] can have a maximum possible sum at column c up to row r. To implement this, I need to go through all rows and columns in the input matrix, and at each index, I also need to go through maximum possible sums at previous row (excluding the same column). This would result in time complexity of O(N*M^2) where N is the number of rows and M is the number of columns.
int getMaxSum(int[][] matrix) {
if (matrix.length == 0) return 0;
int[][] maxSumsDP = new int[matrix.length+1][matrix[0].length];
for (int r = 1; r <= matrix.length; r++) {
for (int c = 0; c < matrix[r-1].length; c++) {
int maxPrev = Integer.MIN_VALUE;
for (int i = 0; i < maxSumDP[r-1].length; i++) {
if (i == c) continue;
maxPrev = Math.max(maxPrev, maxSumsDP[r-1][i]);
}
maxSumsDP[r][c] = maxPrev + matrix[r-1][c];
}
}
int result = maxSumsDP[maxSumsDP.length-1][0];
for (int i = 1; i < maxSumsDP[maxSumsDP.length-1].length; i++) {
result = Math.max(result, maxSumsDP[maxSumsDP.length-1][i]);
}
return result;
}

Related

Minimum Coin Change Top Down DP with 1D array

This is coin change problem from Leetcode where you have infinite coins for given denominations and you have to find minimum coins required to meet the given sum.
I tried solving this problem using 1D cache array with top-down approach. Basic test cases were passed but it failed for some larger values of the sum and denominations. My assumption is that I am doing something wrong while traversing the array, might be missing some calculations for subproblems, but not able to find the issue to fix it.
Problem Statement:
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
My Solution:
/* Test case, it's failing for:
Input: coins: [186,419,83,408]
sum = 6249
Output: 26
Expected: 20
*/
------------------------------------------------------------------------
int fncUtil(int dp[], int a[], int sum, int n, int curCoins) {
if(sum == 0) {
return curCoins;
}
if(n < 0 || sum < 1) {
return Integer.MAX_VALUE;
}
if(dp[sum] != Integer.MAX_VALUE) {
return dp[sum];
}
dp[sum] = Math.min(fncUtil(dp, a, sum - a[n], n, curCoins+1),
fncUtil(dp, a, sum, n-1, curCoins));
return dp[sum];
}
public int coinChange(int[] a, int sum) {
Arrays.sort(a);
int n = a.length;
// minCoins = Integer.MAX_VALUE;
int dp[] = new int[sum+1];
for(int i = 0; i <= sum; i++) {
dp[i] = Integer.MAX_VALUE;
}
dp[0] = 0;
int minCoins = fncUtil(dp, a, sum, n-1, 0);
if(minCoins == Integer.MAX_VALUE) return -1;
return minCoins;
}
Seems you don't update dp array in the case of existing value
if(dp[sum] != Integer.MAX_VALUE) {
return dp[sum];
}
Perhaps you need to choose best from three variants
dp[sum] = Math.min(dp[sum],
Math.min(fncUtil(dp, a, sum - a[n], n, curCoins+1), fncUtil(dp, a, sum, n-1, curCoins)));
But we can solve this problem without recursion using bottom-up order (not checked)
public int coinChange(int[] a, int sum) {
int n = a.length;
int dp[] = new int[sum+1];
for(int i = 0; i <= sum; i++) {
dp[i] = Integer.MAX_VALUE - 1;
}
dp[0] = 0;
for(int i = 0; i < n; i++) {
for (int k = a[i]; k <= sum; k++) {
dp[k] = Math.min(dp[k], dp[k-a[i]] + 1);
}
}
return dp[sum];
}

Given an m x n matrix of 0s and 1s, if an element is 0, set its entire row and column to 0

Given an m x n matrix of 0s and 1s, if an element is 0, set its entire row and column to 0
How can we solve this problem without any extra space complexity
Use first row and first column as list of flags for marking corresponding column and row respectively. So in total, there would be m+n-1 flags available to you for mxn matrix, only one extra flag would be needed to mark 1st row or 1st column (its upon programmer to choose, doesn't make difference though).
[C0/R0] C1 C2 ... Cn-1
R1
R2
.
Rm-1
Take one extra flag for [R0/C0].
Then traverse through the matrix, marking the flags if any of element in the column or row is 0.
Then once you finish traversing, use those flags to decide which column or row would be filled with all 0's.
A naive approach would be to simply iterate the whole matrix:
for i in 1 to number of rows
for j in 1 to number of columns
if n(i,j) == 0:
for all n(i, 1 to number of columns): set to 0
for all n(1 to number of rows, j): set to 0
This doesn't require any additional space besides the the two loop counters. Of course, it is O(scary) regarding performance, but you didn't ask about that.
In order to enhance performance, you could collect all row and column indexes that contain 1; and zero-ize them just once; but that would mean: allocating space for those indexes.
Reduce the space used to O(1) by using boolean variables (and not boolean array)
check if first row & column are zero. If yes, set the corresponding boolean variables: rowZero and colZero
iterate through the remaining rows & columns and mark them as zero wherever applicable
if the first row/column is not zero, then use the methods to mark them as zero
public static void ZeroMatrixResultBitVector(int[][] matrix)
{
bool rowZero = false;
bool colZero = false;
// check if first row has zero
for (int i = 0; i < matrix.Length; i++)
{
if (matrix[i][0] == 0)
{
colZero = true;
break;
}
}
// check if first column is zero
for (int j = 0; j < matrix[0].Length; j++)
{
if (matrix[0][j] == 0)
{
rowZero = true;
break;
}
}
//if the above hasn't been true then we will update the first column/row later
for (int i = 1; i < matrix.Length; i++)
{
for (int j = 1; j < matrix[0].Length; j++)
{
if (matrix[i][j] == 0)
{
matrix[i][0] = 0;
matrix[0][j] = 0;
}
}
}
//nullify all row related records
for (int i = 1; i < matrix.Length; i++)
{
if (matrix[i][0] == 0)
{
nullifyRow(matrix, i);
}
}
//nullify all column related records
for (int j = 1; j < matrix[0].Length; j++)
{
if (matrix[0][j] == 0)
{
nullifyColumn(matrix, j);
}
}
if (rowZero)
{
nullifyRow(matrix, 0);
}
if (colZero)
{
nullifyColumn(matrix, 0);
}
}
Function to nullify Rows:
private static void nullifyRow(int[][] matrix, int row)
{
for (int j = 0; j < matrix[0].Length; j++)
{
matrix[row][j] = 0;
}
}
Function to nullify column:
private static void nullifyColumn(int[][] matrix, int column)
{
for (int i = 0; i < matrix[0].Length; i++)
{
matrix[i][column] = 0;
}
}

Number of 0's in a sorted boolean n*n matrix in log(n) time

This is a google interview question.
You are given a matrix with N rows and N columns. Elements in matrix can be either 1 or 0. Each row and column of matrix is sorted in ascending order. Find number of 0-s in the given matrix.
I had come up with a O(n) solution, but not able to at all come with a O(logn) solution. Any pointers are highly appreciated.
EDIT: It seems O(logn) seems not possible, as explained below.
First, here is an algorithm that counts the zeroes in O(n) time:
countZeroes(matrix):
n = matrix.rowCount
i = 0
j = n-1
count = 0
while i < n && j >=0:
if matrix[i][j] == 1 then:
j--
else:
i++
count += j+1
return count
As each iteration either increments i or decrements j, and both can only take values between 0..n-1 before the loop ends, the maximum number of iterations is 2n, which is O(n).
Here is a JavaScript snippet that generates a 5x5 random matrix and counts the zeroes with the above algorithm:
function countZeroes(matrix) {
var n = matrix.length,
i = 0,
j = n-1,
count = 0;
while (i < n && j >=0) {
if (matrix[i][j] === 1) {
j--;
} else {
i++;
count += j+1;
}
}
return count;
}
function randomMatrix(n) {
var matrix = [],
zeroCounts = [];
for (var i = 0; i < n; i++) {
zeroCounts[i] = Math.floor(Math.random() * (n+1));
}
zeroCounts.sort((a,b) => b-a); // descending
for (var i = 0; i < n; i++) {
matrix[i] = [];
for (var j = 0; j < n; j++) {
matrix[i][j] = j < zeroCounts[i] ? 0 : 1;
}
}
return matrix;
}
function matrixToString(matrix) {
var s = '';
for (var i = 0; i < matrix.length; i++) {
s += matrix[i].join('') + '\n';
}
return s;
}
var matrix = randomMatrix(5);
console.log(matrixToString(matrix));
console.log('Zeroes: ', countZeroes(matrix));
Can it be done in O(log n)?
Imagine a matrix like this:
0000
0001
0011
0111
You will need to visit every row in this matrix to know how many zeroes there are in it. Imagine you would visit only 3 of the 4 rows: it could be any 3... There would still be at least three possible outcomes for the total number of zeroes unless you also visit that fourth one.
For instance if you would have visited row 0, row 1 and row 3, you would know this:
0000
0001
****
0111
By the fact that the rows and columns are sorted, you can deduct:
0000
0001
0**1
0111
But the remaining ** could be 00, 01 or 11. The only way to find out is to actually look at at least one value in that row.
Conclusion: it is not possible in less than O(n).
Let's say in the course of the algorithm we have already learned that the matrix is of the following form:
000?
00?1
0?11
?111
We cannot learn the value of any ? from the value of any other ?, so we need to look at each one of them. Thus, any solution to the general problem needs at least O(n) time, and a solution in log(n) or logĀ²(n) time is impossible.
using binary search to find number of zeros in a row could help out here!
public static int findZerosV2(int[][] NxNMatrix) {
int numZeros = 0;
for (int i = 0; i < NxNMatrix.length; i++) {
int numZerosInRow = binarySearch(NxNMatrix[i]);
if (numZerosInRow > -1) {
numZeros += numZerosInRow;
}
}
return numZeros;
}
public static int binarySearch(int[] rowItem) {
int foundZeros = -1;
int rowIndex = 0;
int highIndex = rowItem.length;
for (int i = 0; i < rowItem.length; i++) {
//find the middle element
int mIndex = (rowIndex + highIndex) / 2;
if (rowItem[mIndex] == 0) {
rowIndex = mIndex + 1;
//keep count using index number of 0
foundZeros = mIndex;
} else
highIndex = mIndex - 1;
}
//considering zero based index array
return foundZeros + 1;
}
you can use a binarysearch on every row to find the position where 0 changes to 1.
Binarysearch is working on an sorted array in O(log n). you will get out the indexnumber of the changed position. this you should do for every row (n times) and then the time will be O(n* log n)
Binary search the "middle" point on the anti-diagonal, then you'll know that the upper-left sub-matrix is full of 0 and the lower-right full of 1. Recursive search on lower-left and lower-right sub-matrices?

Codeforces Round #255 "Modifying matrix" solution(Div-1 B)?

I was trying to solve the "DZY Loves Modification" problem from Round #255 of CodeForces.
Problem link:
http://codeforces.com/contest/446/problem/B.
I am getting wrong answers for the system test cases.
My approach is as follows:
Construct two max-heaps - one heap for storing the row totals and
one for the column totals
Store two variables - rowReductionValue and colReductionValue -
these variables store the value that should be subtracted before
using a row or column's total sum.
For each iteration, choose the entry with maximum value from the
rowSum and colSum heaps
If a row is chosen, the row's total is added to the result and then
the row total is reduced by P * (number_of_columns)
After this, each column's value reduces by P. So, this P is
added to colReductionValue.
An analogous approach is used if a column is chosen.
This approach results in wrong answers.
I am sorry if I was not clear in explaining my approach, I wanted it to be as concise as possible.
Any light on the right approach or the flaw with this approach is much appreciated.
The code is below:
long long getMaxResult(int rows, int cols, int reductionValue, int K)
{
vector<long long> rowSums, colSums;
long long rowReductionValue = 0, colReductionValue = 0, result = 0;
for(int row = 0; row < rows; ++row)
{
long long sum = 0;
for(int col = 0; col < cols; ++col)
{
sum += a[row][col];
}
rowSums.push_back(sum);
}
for(int col = 0; col < cols; ++col)
{
long long sum = 0;
for(int row = 0; row < rows; ++row)
{
sum += a[row][col];
}
colSums.push_back(sum);
}
make_heap(rowSums.begin(), rowSums.end());
make_heap(colSums.begin(), colSums.end());
for(int k = 0; k < K; ++k)
{
pop_heap(rowSums.begin(), rowSums.end());
long long rowMax = rowSums.back();
rowSums.pop_back();
pop_heap(colSums.begin(), colSums.end());
long long colMax = colSums.back();
colSums.pop_back();
if(rowMax - rowReductionValue >= colMax - colReductionValue)
{
result += rowMax - rowReductionValue;
rowMax -= reductionValue * cols;
colReductionValue += reductionValue;
}
else
{
result += colMax - colReductionValue;
colMax -= reductionValue * rows;
rowReductionValue += reductionValue;
}
rowSums.push_back(rowMax);
push_heap(rowSums.begin(), rowSums.end());
colSums.push_back(colMax);
push_heap(colSums.begin(), colSums.end());
}
return result;
}
Thanks-
I'll walk you through the Greedy-Brute Force concept that I used to approach this problem:
If p = 0, apparently the best choice is choosing the row or column which can give greatest pleasure value each time.
Let's ignore p first, then we can get a greatest number ans using previous statement. Now if we choose rows for i times, choose column for k-i times, ans should be ansi - ((k-i) X i X p).
So we could enumerate i from 0 to k and calculate ansi - ((k-i) X i X p) each time, max{ansi - ((k-i) X i X p)} is the maximum possible pleasure value DZY could get.
Let ai be the maximum pleasure value we can get after choosing i rows and bi be the maximum pleasure value we can get after choosing i columns. Then ansi = ai+bk-i. We can use two priority queues to calculate ai and bi quickly.
Good luck!

find the largest sub- matrix full of ones in linear time

Given an n by n matrix with zeros and ones, find the largest sub-
matrix full of ones in linear time. I was told that a solution with
O(n) time complexity exists. If there are n^2 elements in a n X n
matrix how does a linear solution exist?
Unless you have a non-standard definition of submatrix this problem is NP-hard by reduction from maximum clique.
You can't search a n x n matrix in n time. Counterexample: a matrix of zeros with a single element set to one. You have to check every element to find where that one is, so time must be at least O(n^2).
Now if you say that the matrix has N = n^2 entries, and you only consider submatrices that form a contiguous block, then you should be able to find the largest submatrix by walking diagonally across the matrix, keeping track of every rectangle of ones as you go. You could in general have up to O(sqrt(N)) rectangles active simultaneously, and you would need to search in them to figure out which rectangle was the largest, so you ought to be able to do this in O(N^(3/2) * log(N)) time.
If you can pick arbitrary rows and columns to form your submatrix, then I don't see any obvious polynomial time algorithm.
The solution is linear in the number of entries, not in the number of rows or columns.
public static int biggestSubMatrix(int[][] matrix) {
int[][] newMatrix = new int[matrix.length][matrix[0].length];
for (int i = 0; i < matrix.length; i++) {
int sum = 0;
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 1) {
sum++;
newMatrix[i][j] = sum;
} else {
sum = 0;
newMatrix[i][j] = 0;
}
}
}
int maxDimention = 0;
int maxSubMatrix = 0;
for (int i = 0; i < newMatrix[0].length; i++) {
//find dimention for each column
maxDimention = calcHighestDimentionBySmallestItem(newMatrix, i);
if(maxSubMatrix < maxDimention ){
maxSubMatrix = maxDimention ;
}
}
return maxSubMatrix;
}
private static int calcHighestDimentionBySmallestItem(int[][] matrix, int col) {
int totalMaxDimention =0;
for (int j = 0; j < matrix.length; j++) {
int maxDimention = matrix[j][col];
int numItems = 0;
int min = matrix[j][col];
int dimention = 0;
for (int i = j; i < matrix.length; i++) {
int val = matrix[i][col];
if (val != 0) {
if (val < min) {
min = val;
}
numItems++;
dimention = numItems*min;
if(dimention>maxDimention){
maxDimention = dimention;
}
} else { //case val == 0
numItems = 0;
min = 0;
}
}
if(totalMaxDimention < maxDimention){
totalMaxDimention = maxDimention;
}
}
return totalMaxDimention;
}

Resources