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;
}
Related
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];
}
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;
}
Given an array A and a sum, I want to find out if there exists a subsequence of length K such that the sum of all elements in the subsequence equals the given sum.
Code:
for i in(1,N):
for len in (i-1,0):
for sum in (0,Sum of all element)
Possible[len+1][sum] |= Possible[len][sum-A[i]]
Time complexity O(N^2.Sum). Is there any way to improve the time complexity to O(N.Sum)
My function shifts a window of k adjacent array items across the array A and keeps the sum up-to-data until it matches of the search fails.
int getSubSequenceStart(int A[], size_t len, int sum, size_t k)
{
int sumK = 0;
assert(len > 0);
assert(k <= len);
// compute sum for first k items
for (int i = 0; i < k; i++)
{
sumK += A[i];
}
// shift k-window upto end of A
for (int j = k; j < len; j++)
{
if (sumK == sum)
{
return j - k;
}
sumK += A[j] - A[j - k];
}
return -1;
}
Complexity is linear with the length of array A.
Update for the non-contiguous general subarray case:
To find a possibly non-contiguous subarray, you could transform your problem into a subset sum problem by subtracting sum/k from every element of A and looking for a subset with sum zero. The complexity of the subset sum problem is known to be exponential. Therefore, you cannot hope for a linear algorithm, unless your array A has special properties.
Edit:
This could actually be solved without the queue in linear time (negative numbers allowed).
C# code:
bool SubsequenceExists(int[] a, int k, int sum)
{
int currentSum = 0;
if (a.Length < k) return false;
for (int i = 0; i < a.Length; i++)
{
if (i < k)
{
currentSum += a[i];
continue;
}
if (currentSum == sum) return true;
currentSum += a[i] - a[i-k];
}
return false;
}
Original answer:
Assuming you can use a queue of length K something like that should do the job in linear time.
C# code:
bool SubsequenceExists(int[] a, int k, int sum)
{
int currentSum = 0;
var queue = new Queue<int>();
for (int i = 0; i < a.Length; i++)
{
if (i < k)
{
queue.Enqueue(a[i]);
currentSum += a[i];
continue;
}
if (currentSum == sum) return true;
currentSum -= queue.Dequeue();
queue.Enqueue(a[i]);
currentSum += a[i];
}
return false;
}
The logic behind that is pretty much straightforward:
We populate a queue with first K elements while also storing its sum somewhere.
If the resulting sum is not equal to sum then we dequeue an element from the queue and add the next one from A (while updating the sum).
We repeat step 2 until we either reach the end of sequence or find the matching subsequence.
Ta-daa!
Let is_subset_sum(int set[], int n, int sum) be the function to find whether there is a subset of set[] with sum equal to sum. n is the number of elements in set[].
The is_subset_sum problem can be divided into two subproblems
Include the last element, recur for n = n-1, sum = sum – set[n-1]
Exclude the last element, recur for n = n-1.
If any of the above subproblems return true, then return true.
Following is the recursive formula for is_subset_sum() problem.
is_subset_sum(set, n, sum) = is_subset_sum(set, n-1, sum) || is_subset_sum(set, n-1, sum-set[n-1])
Base Cases:
is_subset_sum(set, n, sum) = false, if sum > 0 and n == 0
is_subset_sum(set, n, sum) = true, if sum == 0
We can solve the problem in Pseudo-polynomial time using Dynamic programming. We create a boolean 2D table subset[][] and fill it in a bottom-up manner. The value of subset[i][j] will be true if there is a subset of set[0..j-1] with sum equal to i., otherwise false. Finally, we return subset[sum][n]
The time complexity of the solution is O(sum*n).
Implementation in C
// A Dynamic Programming solution for subset sum problem
#include <stdio.h>
// Returns true if there is a subset of set[] with sun equal to given sum
bool is_subset_sum(int set[], int n, int sum) {
// The value of subset[i][j] will be true if there is a
// subset of set[0..j-1] with sum equal to i
bool subset[sum+1][n+1];
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
subset[0][i] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= sum; i++)
subset[i][0] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= sum; i++) {
for (int j = 1; j <= n; j++) {
subset[i][j] = subset[i][j-1];
if (i >= set[j-1])
subset[i][j] = subset[i][j] || subset[i - set[j-1]][j-1];
}
}
/* // uncomment this code to print table
for (int i = 0; i <= sum; i++) {
for (int j = 0; j <= n; j++)
printf ("%4d", subset[i][j]);
printf("\n");
} */
return subset[sum][n];
}
// Driver program to test above function
int main() {
int set[] = {3, 34, 4, 12, 5, 2};
int sum = 9;
int n = sizeof(set)/sizeof(set[0]);
if (is_subset_sum(set, n, sum) == true)
printf("Found a subset with given sum");
else
printf("No subset with given sum");
return 0;
}
For example,
we have
{2,2,-1},
when k = 0, return -1.
when k = 3, return 3.
This is even tricky because we have negative numbers and an additional variable k. k can be any value, negative, don't make any assumption.
I cannot refer to https://en.wikipedia.org/wiki/Maximum_subarray_problem and https://www.youtube.com/watch?v=yCQN096CwWM to solve this problem.
Can any body help me? Better use Java or JavaScript.
Here is a classic algorithm o(n) for the maximum(no variable k):
public int maxSubArray(int[] nums) {
int max = nums[0];
int tsum = nums[0];
for(int i=1;i<nums.length;i++){
tsum = Math.max(tsum+nums[i],nums[i]);
max = Math.max(max,tsum);
}
return max;
}
This is an o(nlogn) solution referred to
https://www.quora.com/Given-an-array-of-integers-A-and-an-integer-k-find-a-subarray-that-contains-the-largest-sum-subject-to-a-constraint-that-the-sum-is-less-than-k
private int maxSumSubArray(int[] a , int k){
int max = Integer.MIN_VALUE;
int sumj = 0;
TreeSet<Integer> ts = new TreeSet();
ts.add(0);
for(int i=0;i<a.length;i++){
sumj += a[i];
if (sumj == k) return k;
Integer gap = ts.ceiling(sumj - k);
if(gap != null) max = Math.max(max, sumj - gap);
ts.add(sumj);
}
return max;
}
I was influenced by the classic solution mentioned in the question.
This problem can be simply solved by an o(n^2) solution:
private int maxSumSubArray(int[] a , int k){
int max = Integer.MIN_VALUE;
for(int i=0;i<a.length;i++){
int tsum = 0;
for(int j=i;j<a.length;j++){
tsum += a[j];
if(tsum <= k) max=Math.max(max,tsum);
}
}
return max;
}
Here's a naive algorithm that runs in O(n²).
std::array<int, 3> input = {2, 2, -1};
int k = -1;
int sum = 0, largestSum = *std::min_element(input.begin(), input.end()) -1;
int i = 0, j = 0;
int start = 0, end = 0;
while (largestSum != k && i != input.size()) {
sum += input[j];
if (sum <= k && sum > largestSum) {
largestSum = sum;
start = i;
end = j;
}
++j;
if (j == input.size()) {
++i;
j = i;
sum = 0;
}
}
That's C++ but it shouldn't be hard to write in Java or Javascript.
It basically tries every sum possible (there are n*(n+1)/2) and stops if it finds k.
largestSum must be initialized to a low-enough value. Since the minimum element of the input could equal k, I subtracted 1 to it.
start and end are the first and last indices of the final subarray.
Of course, it could be improved if you had any constraints on the inputs.
Live example
Here's one in python O(n^2):
def maxsubfunc(arr, k):
s = 0
maxsofar = -1
for i,n in enumerate(arr):
s += n
if s <= k:
maxsofar = max(maxsofar, s)
else:
maxnow = s
for j in range(i):
maxnow -= arr[j]
if maxnow < k:
maxsofar = max(maxnow, maxsofar)
return maxsofar
Wonder why no one's discussing the Sliding Window based Solution for this( O(n) ).
Initialise the window with first element. Keep track of start index of window.
Iterate over the array, adding the current element to window.
If sum becomes > k, reduce the window from start until sum becomes <= k.
Check if sum > maxSumSoFar, set maxSumSoFar = sum.
Note -> 'sum' in above algo is the sum of elements in current window.
int findMaxSubarraySum(long long arr[], int N, long long K)
{
long long currSum = arr[0];
long long maxSum = LLONG_MIN;
int startIndex = 0;
if(currSum <= X) maxSum = currSum;
for(int i=1; i<N; i++){
currSum += arr[i];
while(currSum > K && startIndex <= i){
currSum -= arr[startIndex];
startIndex++;
}
if(currSum <= K) maxSum = max(maxSum, currSum);
}
return (int)maxSum;
}
Can be solved using simple sliding window. First keep adding sum of array elements and if sum exceeds k decrease it by subtracting elements from start. This works only if array has non-negative numbers.
int curr_sum = arr[0], max_sum = 0, start = 0;
// To find max_sum less than sum
for (int i = 1; i < n; i++) {
// Update max_sum if it becomes
// greater than curr_sum
if (curr_sum <= sum)
max_sum = max(max_sum, curr_sum);
// If curr_sum becomes greater than
// sum subtract starting elements of array
while (curr_sum + arr[i] > sum && start < i) {
curr_sum -= arr[start];
start++;
}
// Add elements to curr_sum
curr_sum += arr[i];
}
// Adding an extra check for last subarray
if (curr_sum <= sum)
max_sum = max(max_sum, curr_sum);
return max_sum;
# 3 steps to solve Kadane's Algorithm
//approach
sum=0
maxi=arr[0]
for i=0 to arr.length {
//steps
1. sum=sum+arr[i]
2. maxi=max(maxi,sum)
3. if(sum<0) -> sum=0
}
return maxi
//solution
nums=[-2,1,-3,4,-1,2,1,-5,4]
class Solution {
public int maxSubArray(int[] nums) {
int sum=0;
int maxi=nums[0];
for(int i=0 ; i<nums.length ; i++){
sum+=nums[i];
maxi=Math.max(maxi,sum);
if(sum<0){
sum=0;
}
}
return maxi;
}
Here is the given example:
We have the function which takes one matrix and it's number of columns and it's number of rows and returns int (this is gonna be length). For example:
int function (int** matrix, int n, int m)
The question is what's the fastest algorithm for implementing this function so it returns the maximum length of consecutive fields with the same value (doesn't matter if those same values are in one column or in one row, in this example on picture it's the 5 fields of one column with value 8)?
Values can be from 0-255 (grayscale for example).
So in the given example function should return 5.
If this is a bottleneck and the matrix is large, the first optimization to try is to make one pass over the matrix in sequential memory order (row-by-row in C or C++) rather than two. This is because it's very expensive to traverse a 2d array in the other direction. Cache and paging behavior are the worst possible.
For this you will need a row-sized array to track the number of consecutive values in the current run within each column.
int function (int a[][], int m, int n) {
if (n <= 0 || m <= 0) return 0;
int longest_run_len = 1; // Accumulator for the return value.
int current_col_run_len[n]; // Accumulators for each column
int current_row_run_len = 1; // Accumulator for the current row.
// Initialize the column accumulators and check the first row.
current_col_run_len[0] = 1;
for (int j = 1; j < n; j++) {
current_col_run_len[j] = 1;
if (a[0][j] == a[0][j-1]) {
if (++current_row_run_len > longest_run_len)
longest_run_len = current_row_run_len;
} else current_row_run_len = 1;
}
// Now the rest of the rows...
for (int i = 1; i < m; i++) {
// First column:
if (a[i][0] == a[i-1][0]) {
if (++current_col_run_len[0] > longest_run_len)
longest_run_len = current_col_run_len[0];
} else current_col_run_len[0] = 1;
// Other columns.
current_row_run_len = 1;
for (int j = 1; j < n; j++) {
if (a[i][j] == a[i][j-1]) {
if (++current_row_run_len > longest_run_len)
longest_run_len = current_row_run_len;
} else current_row_run_len = 1;
if (a[i][j] == a[i-1][j]) {
if (++current_col_run_len[j] > longest_run_len)
longest_run_len = current_col_run_len[j];
} else current_col_run_len[j] = 1;
}
}
return longest_run_len;
}
You need to pass over each entry of the matrix at least once, so you can't possible do better than O(m*n).
The most straightforward way is to pass over each row and each column once. This will be two passes over the matrix, but the algorithm is still O(m*n).
Any attempt to do it in one pass will probably be a lot more complex.
int function (int** matrix, int n, int m) {
int best=1;
for (int i=0; i<m; ++i) {
int k=1;
int last=-1;
for (int j=0; j<n; ++j) {
if (matrix[i][j] == last) {
k++;
if (k > best) {
best=k;
}
}
else {
k=1;
}
last = matrix[i][j];
}
}
for (int j=0; j<n; ++j) {
int k=1;
int last=-1;
for (int i=0; i<m; ++i) {
if (matrix[i][j] == last) {
k++;
if (k > best) {
best=k;
}
}
else {
k=1;
}
last = matrix[i][j];
}
}
return best;
}