Number of submatrix with sum k - arrays

I just came around this question in a programming contest and was unable to solve it within required time constraints.So just curious to get the right approach.Any suggestions would be helpful.
Input
Given a matix a[] with n elements where n<1000.
an integer k where k<10^9
Construct a new matrix b where b[i][j]=a[i]*a[j].
Output
Number of possible submatrix with sum k.
Test case
a[]={1,-1}
k=0
output=5
explaination
b={ 1,-1,
-1, 1}
so 2 row subsets,2 column subsets and 1 complete array. so total 5.
I tried to solve using something like this https://math.stackexchange.com/questions/639172/submatrix-with-sum-k

For a sub array sum b[i][j] -> b[i + m]b[j + n], it is equals to
X = a[i]*(a[j] + a[j + 1] + ... + a[j + n])
+ a[i + 1]*(a[j] + a[j + 1] + ... + a[j + n])
+ ...
+ a[i + m]*(a[j] + a[j + 1] + ... + a[j + n])
= sum(a[i] + ..a[i + m])*sum(a[j] +... a[j + n])
So, the task is reduced to find two segments in array a, and their sums multiply together equals to k.
To find all segments sum in a, it can be done in O(n^2).
Store all of the sum in a HashSet, or similar, and we can find the answer in O(n^2) time complexity.

Related

Sum of subarray multiplied by last element of subarray

Given an array find all sub-arrays and multiply it by last element of sub-array and find summation .
E.g : [1,2,3]
ans = 1*1 + 2*2 +3*3 + (1+2)*2 + (2+3)*3 + (1+2+3)*3 = 53
I've tried following logic:
init_sum = sum (array)
prev = array[0];
ans = 0
for i = 1 to n:
ans += array[i]* array[i]*(init_sum-prev)
init_sum -= prev
prev = array[i]
end loop
ans += sum(array)
print(ans)
But this does not work for array with repeated elements
E.g : [1,3,3] , I'm getting ans = 88 where it should be 70.
Any hint would be appreciated .
There is a recursive formula for each element of the array.
For each element ith, we can notice that the contribution of this element to the overall sum is equaled to the sum of all sub array that end at this element times the value of this element itself.
I.e
For array data[a, b, c, d], the result will be:
result = a * a
+ ((a + b) + b) * b
+ ((a + b + c) + (b + c) + c) * c
+ ((a + b + c + d) + (b + c + d) + (c + d) + d) * d
Call the factor to be multiplied with the value of ith element is xi, we make one observation that
xi = x(i - 1) + i*data[i]
So, in case of the above array
x1 = a
x2 = ((a + b) + b) = x1 + 2*b
x3 = ((a + b + c) + (b + c) + c) = x2 + 3*c
x4 = ((a + b + c + d) + (b + c + d) + (c + d) + d) = x3 + 4*d
Thus, we have our solution
init_sum = 0
ans = 0
for i = 0 to n:
init_sum = init_sum + (i + 1)*array[i]
ans += init_sum*array[i]
end loop
print(ans)
The algorithm you are after can be divided into the following steps:
1- Generate the power set of the given array.
2- For each set, add each element in the array, pick the last element in the current set and add multiply it with the sum of the set. Add this sum to the totalsum
Lets see this in action for [1 3 3], I use the algorithm below to generate the power set and store it in res
Step 1:
void generateSubsets(int i, vector<int>& nums, vector<int>& holder, vector<vector<int>>& res)
{
if(i >= nums.size())
{
res.push_back(holder);
return;
}
holder.push_back(nums[i]);
generateSubsets(i+1,nums,holder,res);
holder.pop_back();
generateSubsets(i+1,nums,holder,res);
}
Where I call this function as:
vector<vector<int>> res;
vector<int> holder;
vector<int> nums = {1,3,3};
generateSubsets(0,nums,holder,res);
The generated subsets in res are:
[1 3 3],[1 3],[1 3],[1],[3 3],[3],[3]
Step 2 : Add each element in the set and multiply by last element of the set, so we have.
[1+3+3]*3 + [1+3]*3 + [1+3]*3 + [1]*1 + [3*3]*3 + [3]*3 + [3]*3
Cumulative totalsum will then be:
totalsum = 21 + 12 + 12 + 1 + 18 + 3 + 3 = 70

Given an array of `first n` natural numbers with one element missing and one duplicate element. Figure out both numbers [duplicate]

This question already has answers here:
Find the missing and duplicate elements in an array in linear time and constant space
(8 answers)
Closed 4 years ago.
Given an array of first n natural numbers with one element missing and one duplicate element. figure out both numbers. I was asked this question in one of the interviews.
For example, the sample array is
5, 2, 1, 4, 5
where n=5
Answer for the given array should be:
missing element = 3
duplicate element = 5
Is it possible to come-up with the solution without iterating the array.
I was able to come-up with a solution having complexity O(nlogn), without extra space. Does any O(n) solution exist (without extra space)?
Let's say that you have numbers 1,...,n. Now, denote their sum 1 + 2 + ... + n as S. If we denote the missing number as j and the duplicit one as k, we will get for the modified sum S' = S - j + k, so that's one equation for two variables. We can repeat the same procedure, but this time, summing second powers, thus S_2 = 1 + 4 + ... + n^2. For the sequence with one missing and one duplicit number, the result will be S_2' = S_2 - j*j + k*k. Thus we get two equations for two variables.
In total, we have:
S' = S - j + k
S_2' = S_2 - j*j + k*k
therefore
k - j = S' - S =: a
k*k - j*j = S_2' - S_2 =: b
where we introduced the symbols a and b to simplify the notation.
Now, k*k - j*j = (k - j)*(k + j), thus:
k - j = a
k*k - j*j = a * (k + j) = b
summing both equations gives:
2*k = b/a + a
2*j = b/a - a
For your particular example:
S = 1 + 2 + 3 + 4 + 5 = 15
S_2 = 1 + 4 + 9 + 16 + 25 = 55
For the series with one missing and one duplicit element:
S' = 5 + 2 + 1 + 4 + 5 = 17
S_2' = 25 + 4 + 1 + 16 + 25 = 71
then:
a = S' - S = 2
b = S_2' - S_2 = 16
therefore:
2*k = 8 + 2 = 10
2*j = 8 - 2 = 6
which gives:
k = 5, j = 3
In practice (as noted by #HermanTheGermanHesse), one can obtain closed-form expressions for S as well as S_2 in terms of polynomials in n (so-called Faulhaber's formulae), namely: S = n*(n+1)/2 and S_2 = n*(n+1)*(2*n+1)/6. Therefore it is just sufficient to go once over the input data, accumulate S' and S_2', and use the formulae for k and j given above...

Given 3 sorted arrays A, B, C and number S, find i, j, k such that A[i] + B[j] + C[k] = S

I've just found out how to solve this in O(n^2 log n) time (assuming each array has the same length):
for each A[i]:
for each B[j]:
if A[i] + B[j] + C.binarySearch(S - A[i] - B[j]) == S:
return (i, j, k)
Is there any way to solve this in O(n^2) time or to improve the above algorithm?
The algorithm you have ain't bad. Relative to n^2, log(n) grows so slowly that it can practically be considered a constant. For example, for n = 1000000, n^2 = 1000000000000 and log(n) = 20. Once n becomes large enough for log(n) to have any significant influence, n^2 will already be so big that the result cannot be computed anyway.
A solution, inspired by #YvesDaoust, though I'm not sure if it's exactly the same:
For every A[i], calculate the remainder R = S - A[i] which should be a combination of some B[j] and C[k];
Let j = 0 and k = |C|-1 (the last index in C);
If B[j] + C[k] < R, increase j;
If B[j] + C[k] > R, decrease k;
Repeat the two previous steps until B[j] + C[k] = R or j >= |B| or k < 0
I suggest not to complicate the algorithm too much with micro-optimizations. For any reasonably small set of numbers and it will be fast enough. If the arrays become too large for this approach, your problem would make a good candidate for Machine Learning approaches such as Hill Climbing.
if the arrays are of non-negatives
* you can trim all 3 arrays to at S => A[n] > S
* similarly, dont bother checking array C if A[aIdx] + B[bIdx] > S
prepare:
sort each array ascending +O(N.log(n))
implement binary search on each array ?O(log(N))
compute:
i=bin_search(smallest i that A[i]+B[0]+C[0]>=S); for (;i<Na;i++) { if (A[i]+B[0]+C[0]>S) break;
j=bin_search(smallest j that A[i]+B[j]+C[0]>=S); for (;j<Nb;j++) { if (A[i]+B[j]+C[0]>S) break;
ss=S-A[i]-B[j];
if (ss<0) break;
k=bin_search(ss);
if (k found) return; // found solution is: i,j,k
}
}
if I see it right and: N=max(Na,Nb,Nc), M=max(valid intervals A,B,C) ... M<=N
it is (3*N.log(N)+log(N)+M*log(N)*M*log(N)) -> O((M^2)*log(N))
the j binary search can be called just once and then iterate +1 if needed
the complexity is the same but the N has changed
for average conditions is this much much faster because M<<N
The O(N²) solution is very simple.
First consider the case of two arrays, finding A[i] + B[j] = S'.
This can be rewritten as A[i] = S' - B[j] = B'[j]: you need to find equal values in two sorted arrays. This is readily done in linear time with a merging process. (You can explicitly compute the array B' but this is unnecessary, just do it on the fly: instead of fetching B'[j], get S' - B[NB-1-j]).
Having established this procedure, it suffices to use it for all elements of C, in search of S - C[k].
Here is Python code that does that and reports all solutions. (It has been rewritten to be compact and symmetric.)
for k in range(NC):
# Find S - C[k] in top-to-tail merged A and B
i, j= 0, NB - 1
while i < NA and 0 <= j:
if A[i] + B[j] + C[k] < S:
# Move forward A
i+= 1
elif A[i] + B[j] + C[k] > S:
# Move back B
j-= 1
else:
# Found
print A[i] + B[j] + C[k], "=", A[i], "+", B[j], "+", C[k]
i+= 1; j-= 1
Execution with
A= [1, 2, 3, 4, 5, 6, 7]; NA= len(A)
B= [2, 3, 5, 7, 11]; NB= len(B)
C= [1, 1, 2, 3, 5, 7]; NC= len(C)
S= 15
gives
15 = 3 + 11 + 1
15 = 7 + 7 + 1
15 = 3 + 11 + 1
15 = 7 + 7 + 1
15 = 2 + 11 + 2
15 = 6 + 7 + 2
15 = 1 + 11 + 3
15 = 5 + 7 + 3
15 = 7 + 5 + 3
15 = 3 + 7 + 5
15 = 5 + 5 + 5
15 = 7 + 3 + 5
15 = 1 + 7 + 7
15 = 3 + 5 + 7
15 = 5 + 3 + 7
15 = 6 + 2 + 7

What is the running time complexity of the following piece of code?

void foo(int n){
int i = 1, sum = 1;
while (sum <= n) {
i++;
sum+=i;
}
}
What I feel is, the loop will terminate only if the sum becomes greater than the argument n.
And, Sum at jth iteration is: S(j) = S(j-1) + j
S(1) = S(0) + 1
S(2) = S(1) + 2
S(3) = S(2) + 3
...
S(n) = S(n-1) + n
How should I go further? I am stuck at this recurrence relation.
The loop will terminate when 1 + 2 + 3 + ... + j times becomes greater than n. But I am not convinced, if it is okay.
The classic way to prove this is to write the series out twice, in both orders ie:
S(n) = 1 + 2 + 3 + ...+ n-2 + n-1 + n
S(n) = n + (n-1) + (n-2) + ...+ 3 + 2 + 1
If you sum those term by term you get
2S(n)= n+1 + n+1 + n+1 + ... + n+1
With n terms
therefore
S(n) = n*(n+1)/2
(A result allegedly discovered by Gauss as a schoolboy)
From this it follows that it takes O(sqrt(n)) iterations.
You have almost done it. The last thing you have to note is that 1 + 2 + 3 + ... + j is (1 + j) * j / 2, or O(j^2). This is a well-known formula from math (arithmetic progression).
It will break after k iterations when
1 + 2 + .... + k > n
k*(k+1)/2 > n
k*k + k - 2*n >0
k will come to k = (-1 + sqrt(1+8n))/2 (discarding negative value)
Hence, Time complexity is sqrt(n).

Efficiency of growing a dynamic array by a fixed constant each time?

So when a dynamic array is doubled in size each time an element is added, I understand how the time complexity for expanding is O(n) n being the elements. What about if the the array is copied and moved to a new array that is only 1 size bigger when it is full? (instead of doubling) When we resize by some constant C, it the time complexity always O(n)?
If you grow by some fixed constant C, then no, the runtime will not be O(n). Instead, it will be Θ(n2).
To see this, think about what happens if you do a sequence of C consecutive operations. Of those operations, C - 1 of them will take time O(1) because space already exists. The last operation will take time O(n) because it needs to reallocate the array, add space, and copy everything over. Therefore, any sequence of C operations will take time O(n + c).
So now consider what happens if you perform a sequence of n operations. Break those operations up into blocks of size C; there will be n / C of them. The total work required to perform those operations will be
(c + c) + (2c + c) + (3c + c) + ... + (n + c)
= cn / c + (c + 2c + 3c + ... + nc / c)
= n + c(1 + 2 + 3 + ... + n / c)
= n + c(n/c)(n/c + 1)/2
= n + n(n/c + 1)/2
= n + n2 / c + n / 2
= Θ(n2)
Contrast this with the math for when you double the array size whenever you need more space: the total work done is
1 + 2 + 4 + 8 + 16 + 32 + ... + n
= 1 + 2 + 4 + 8 + ... + 2log n
= 2log n + 1 - 1
= 2n - 1
= Θ(n)
Transplanted from SO Documentation.
Sums of powers of 2 — 1 + 2 + 4 + 8 + 16 + …
The sum
20 + 21 + 22 + ... + 2n-1
simplifies to 2n - 1. This explains why the maximum value that can be stored in an unsigned 32-bit integer is 232 - 1.

Resources