In an array A[1...n] of positive integers, you are to count all quadruples in array satisfying:
A[i] + A[j] + A[k] = A[l] where 1 <= i < j < k < l <=n
I tried many things but could not come to a solution better than O(n^3logn)
Can we solve it in O(n^3) or O(n^2) satisfying the ordering constraint of indices?
Why not O(n^2)? If we have
A[i] + A[j] + A[k] = A[l]
where 1 ≤ i < j < k < l ≤ n
and we hashed all
A[i] + A[j] pairs
where 1 ≤ i < j < n - 1
then we can iterate:
l = n
k = n - 1
check if A[l] - A[k] is in the hash
now update on each element as we descend:
j = n - 2
remove each instance of A[j] + A[i] in the hash
where 1 ≤ i < j
for each instance of A[l] - A[j]
where j < l < n
check if a value exists in the hash
j = j - 1
...
Attempt in JavaScript:
function f(A){
if (A.length < 4)
return 0;
let n = A.length;
let hash = {};
let i = 0;
let j;
let k;
let l;
let sum;
let diff;
let count = 0;
// Hash sums up to A[n - 3]
// in O(n^2) time
for (; i<n-3; i++){
for (j=i+1; j<n-2; j++){
sum = A[i] + A[j];
hash[sum] = hash[sum] ? hash[sum] + 1 : 1;
}
}
diff = A[n-1] - A[n-2];
if (hash[diff])
count = count + hash[diff];
// Iterate on j descending,
// updating the hash each time,
// O(n) times
for (; j>1; j--){
// Remove instances of j in
// the hash in O(n) time
for (i=j-1; i>=0; i--){
sum = A[i] + A[j];
hash[sum] = hash[sum] - 1;
}
// Check for valid quadruples
// in O(n) time
// where the old j is now k
k = j;
for (l=k+1; l<n; l++){
diff = A[l] - A[k];
if (hash[diff])
count = count + hash[diff];
}
}
return count;
}
/*
1 1 1 1 3 3
x x x x
x x x x
x x x x
x x x x
x x x x
x x x x
x x x x
x x x x
Total 8
*/
var A = [1,1,1,1,3,3];
console.log(JSON.stringify(A))
console.log(f(A));
There is a solution in O(n^2 + S), where S is count of quadruples satisfying your condition.
Create a hash-based map M that maps integers to lists of pairs of integers (HashMap<Integer, List<Pair<Integer, Integer>>>).
For each pair (i, j) of indices (i < j) add this pair to list M[A[i] + A[j]]. (For-loop by j should be outer and for-loop by i should be nested, so pairs in all lists are sorted by j)
For each pair (k, l) of indices (k < l):
Let L be the list M[A[l] - A[k]]
For pairs (i, j) in L:
If j < k, add (i, j, k, l) to your answer
Else break nested loop, because pairs are sorted by j and following pairs will not satisfy condition j < k
Both outer loops run in O(n^2), nested loop runs only S times through the whole algorithm, so time complexity is O(n^2 + S).
Related
I recently came across this question in one of the coding interviews. The question is as follows:
Given an array A[] of n numbers and a number k, count the total number of distinct subarrays such that each subarray contains at most k odd elements.
1 <= n <= 1000
1 <= A[i] <= 250
1 <= k <= n
I used a DP approach to solve the problem, but my solution does not take care of the distinct part.
public int distinctSubArraysWithAtmostKOddElements(int[] a, int k) {
int l = a.length;
int[][] dp = new int[k + 1][l];
for (int j = 0; j < l; j++) {
dp[0][j] = a[j] % 2 == 0 ? 1 : 0;
}
for (int i = 1; i <= k; i++) {
dp[i][0] = 1;
}
for (int j = 1; j <= k; j++) {
for (int i = 1; i < l; i++) {
if (a[i] % 2 == 0) {
dp[j][i] = Math.max(dp[j - 1][i], 1 + Math.max(dp[j - 1][i - 1], dp[j][i - 1]));
} else {
dp[j][i] = Math.max(dp[j - 1][i], 1 + dp[j - 1][i - 1]);
}
}
}
int tot = 0;
for (int i = 0; i < l; i++) {
tot += dp[k][i];
}
return tot;
}
My solution works in O(nk) time and space.
How can I take care of the distinctness ? Is there a mathematical formula that solves this problem?
Edit:
Eg 1:
A[] = {2,1,2,3} and k = 1
Distinct Subarrays are: {2}, {2,1}, {1}, {1,2}, {2,1,2}, {3}, {2,3}
So answer is 7.
Eg 2:
A[] = {1,1,1} and k = 2
Distinct Subarrays are: {1}, {1,1}
So answer is 2.
Eg 3:
A[] = {1,2,3} and k = 1
Distinct Subarrays are: {1}, {2}, {3}, {1,2}, {2,3}
So answer is 5.
We can iterate over all subarrays and store the hashes of the valid subarrays.The time complexity is O((n^2)*log(n)) and memory complexity O(n^2).
int distinctSubArraysWithAtmostKOddElements(vector<int> a, int k)
{
set<unsigned long long int> hashes;
int prime = 163;
for(int i = 0 ; i < a.size() ; i++)
{
int oddNow = 0;
unsigned long long int hashNow = 0;
for(int j = i ; j < a.size() ; j++)
{
hashNow = hashNow * prime + a[j];
if( a[j] % 2) oddNow++;
if(oddNow <= k)
hashes.insert(hashNow);
else
break;
}
}
return hashes.size();
}
Problem:
Given two arrays A and B, both of size n, find the interval [i,j] (0 <= i,j <= n-1) that maximizes the value of V = sum(A[i:j]) - min(B[i:j]).
Without the array B twist, this problem is just the maximum subarray sum problem, solvable in O(N) with Kadane's algorithm. Now, we have a second array, and we select the minimum element from the range, and deduct it from the sum.
Example:
A = [-5, 2, 3, 4, 5]
B = [-5, 1, 2, 0, -5]
Solution: 19
i=1 to j=4
2+3+4+5 - (-5) = 19
A trivial algorithm is to do a double loop to calculate each (i,j) interval, but this naive approach has O(N^2) time complexity.
I have been trying to find an O(N), or at least an O(NlogN) algorithm, but I haven't been able to achieve it yet.
I would appreciate any ideas on this, thanks!
Edit: The implementation of the solution by Peter for reference:
#include<iostream>
#include<vector>
#include<climits>
using namespace std;
int kadane_modified(vector<int>& A, vector<int>& B){
if(A.empty() || B.empty()) return 0;
int size = A.size();
// Backward Kadane's
vector<int> R(size);
int max_so_far = INT_MIN, max_starting_here = 0;
for (int i = size-1; i >= 0; i--)
{
max_starting_here = max_starting_here + A[i];
if (max_so_far < max_starting_here)
max_so_far = max_starting_here;
if (max_starting_here < 0)
max_starting_here = 0;
R[i] = max_starting_here;
}
// Forward Kadane's
vector<int> F(size);
max_so_far = INT_MIN; int max_ending_here = 0;
for (int i = 0; i < size; i++)
{
max_ending_here = max_ending_here + A[i];
if (max_so_far < max_ending_here)
max_so_far = max_ending_here;
if (max_ending_here < 0)
max_ending_here = 0;
F[i] = max_ending_here;
}
// DP that combines previous results
vector<int> V(size);
for(int k = 0; k < size; k++){
if(k < size-1 & k > 0)
V[k] = A[k] + R[k+1] - B[k] + F[k-1];
else if(k == 0)
V[k] = A[k] - B[k] + R[k+1];
else if(k == size-1)
V[k] = A[k] - B[k] + F[k-1];
}
// The maximum V is our answer
int solution = INT_MIN;
for(int i = 0; i < size; i++){
if(solution < V[i]) solution = V[i];
}
return solution;
}
int main()
{
vector<int> A = {-5, 2, 3, 4, 5};
vector<int> B = {-5, 1, 2, 0, -5};
int solution = kadane_modified(A, B);
cout << solution << endl;
return 0;
}
Output:
19
Kadane's algorithm computes the maximum sum of A ending at each position (call this F[i]).
You can also run Kadane's algorithm on the reversed array A to find the maximum sum of A starting at each position (call this R[i]).
We can then use these two arrays to compute the maximum subarray sum A[i:j]-B[k] where i<=k<=j for each position k (by simply computing F[k-1] + A[k] + R[k+1] - B[k] for each k).
This has then solved the slightly different problem of "Find interval i:j which satisfies i<=k<=j and that maximizes A[i:j] - B[k]". However, the highest value that this takes will be the same as choosing B[k] to be the minimum of B[i:j], so this is equivalent to your original problem.
The complexity of this approach is O(n).
How can I find the largest pair sum in an array of positive integers of size n, but with the integers at least at a distance k? (For example, if the first element is a[i], then the second element should be a[i+k] (or more).)
I tried this:
int max_sum = 0;
int sum;
for (int i = 0 ; i < n; i++) {
for( int j = i + k; j < n; j++) {
sum = arr_sums[i] + arr_sums[j];
if ( sum > max_sum ) {
max_sum = sum;
}
}
}
but it's too slow for large arrays.
It's quite simple to do in O (n), not O (n²) like your solution.
For each j, 0 ≤ j < n,
calculate m [j] = "largest element from a [j] to a [n - 1]. ".
Obviously m [n - 1] = a [n - 1], m [j] = max (a [j], m [j + 1]).
Then for each i, 0 ≤ i < n - k, calculate a [i] + m [i + k],
and pick the largest of these.
It should be obvious how to do this without actually storing the values m [j] except for one.
//assuming we checked first for n<=k
int max_lagged = arr_sums[0];
int max_sum = max_lagged+arr_sums[k];
int sum;
for (int i = k+1 ; i < n; i++) {
if (arr_sums[i-k] > max_lagged) {
max_lagged=arr_sums[i-k];
}
sum = arr_sums[i] + max_lagged;
if ( sum > max_sum ) {
max_sum = sum;
}
}
I need to implement a pretty easy in-place LU-decomposition of matrix A. I'm using Gaussian elimination and I want to test it with a 3x3 matrix. The problem is, I keep getting stack smashing error and I don't have any idea why. I don't see any problems in my code, which could do this. Do you have any idea?
The problem is probably in the Factorization block.
###My code:###
#include <stdio.h>
int main() {
int n = 3; // matrix size
int A[3][3] = {
{1, 4, 7},
{2, 5, 8},
{3, 6, 10}
};
printf("Matrix A:\n");
for( int i=0; i < n; i++ ) {
for( int j=0; j < n; j++ ) {
printf("%d ", A[i][j]);
if ( j % 2 == 0 && j != 0 ) {
printf("\n");
}
}
}
// FACTORIZATION
int k;
int rows;
for( k = 0; k < n; k++ ) {
rows = k + k+1;
A[rows][k] = A[rows][k]/A[k][k];
A[rows][rows] = A[rows][rows] - A[rows][k] * A[k][rows];
printf("k: %d\n", k);
}
printf("Matrix after decomp:\n");
for( int i=0; i < n; i++ ) {
for( int j=0; j < n; j++ ) {
printf("%d ", A[i][j]);
if ( j % 3 == 0 && j != 0 ) {
printf("\n");
}
}
}
return 0;
}
Your error is most likely here:
rows = k + k+1;
A[rows][k] = A[rows][k]/A[k][k];
A[rows][rows] = A[rows][rows] - A[rows][k] * A[k][rows];
This means that rows goes through the values 1, 3, 5; and is then used to access an array with only three elements. That would, indeed, overflow, as the only valid offset among those is 1.
EDIT: Looking at your Matlab code, it is doing something completely different, as rows = k + 1:n sets rows to a small vector, which it then uses the splice the matrix, something C does not support as a primitive. You would need to reimplement both that and the matrix multiplication A(rows, k) * A(k, rows) using explicit loops.
Your original Matlab code was (Matlab has 1-based indexing):
for k = 1:n - 1
rows = k + 1:n
A(rows, k) = A(rows, k) / A(k, k)
A(rows, rows) = A(rows, rows) - A(rows, k) * A(k, rows)
end
What rows = k + 1:n this does is that it sets rows to represent a range. The expression A(rows, k) is actually a reference to a vector-shaped slice of the matrix, and Matlab can divide a vector by a scalar.
On the last line, A(rows, rows) is a matrix-shaped slice , and A(rows, k) * A(k, rows) is a matrix multiplication, e.g. multiplying matrices of dimension (1,3) and (3,1) to get one of (3,3).
In C you can't do that using the builtin = and / operators.
The C equivalent is:
for ( int k = 0; k < n - 1; ++k )
{
// A(rows, k) = A(rows, k) / A(k, k)
for ( int row = k + 1; row < n; ++row )
A[row][k] /= A[k][k];
// A(rows, rows) = A(rows, rows) - A(rows, k) * A(k, rows)
for ( int row = k + 1; row < n; ++row )
for ( int col = k + 1; col < n; ++col )
A[row][col] -= A[row][k] * A[k][col];
}
(disclaimer: untested!)
The first part is straightforward: every value in a vector is being divided by a scalar.
However, the second line is more complicated. The Matlab code includes a matrix multiplication and a matrix subtraction ; and also the operation of extracting a sub-matrix from a matrix. If we tried to write a direct translation of that to C, it is very complicated.
We need to use two nested loops to iterate over the rows and columns to perform this operation on the square matrix.
This is a variation of a Maximum_subarray_problem.
Find contiguous subarray of length at most K, in an array of length N ( 0 <= K <= N )
Eg. given [-13,-1,1,1,2,3,1,1] and K = 2, maximum K-subarray sum is 5
Looking for O(N) solution. The trivial solution is O(N*N), checking range between each pair. I feel it can be improved to O(N).
Let your array be indexed with 1 to n. Let f(i) be the maximum subarray that ends at i and prefixSum(i) be the prefix sum up to (and including) index i. Then we have
f(i) = prefixSum(i) - MIN(j = i - K to i - 1, prefixSum(j))
f(i) can be computed in linear time by using a sliding window minimum data structure. Here's another implementation of the queue, it support enqueue, dequeue and find-max/min. Using that queue as a primitive, the algorithm would look like this in pseudocode:
global_max = -infinity
prefixSum[0] = 0
q = new MinQueue()
for i := 1 to n:
prefixSum[i] = prefixSum[i - 1] + a[i]
if i > 1
q.enqueue(prefixSum[i - 1])
if i - K - 1 >= 1
q.dequeue()
global_max = max(global_max, prefixSum[i] - q.min())
This is Java code that performing the same task in O(n)
public void maxSubSet (int[] array, int k)
{
int startIndex = -1;
int max = 0;
for(int i =0; i<k; i++){ //Assuming k<array.length
max += array[i];
startIndex = 0;
}
for(int i=k; i<array.length; i++){
int sum = array[i] - array[i-k];
if (sum > max){
max = sum;
startIndex = i;
}
}
System.out.println("Max Sum:" + max);
for(int i = startIndex; i<startIndex+k; i++)
System.out.println(i+":"+array[i]);
}