I'm trying to find the time complexity of this algorithm, I tried calculating it using T(n), assumed that T(n) = 2T(n-1) + Const and got O(n) as a result.
bool sum(int arr[], int x, int n, int index){
if(x == 0 && index == 3)
return true;
if(n == 0)
return false;
if (index == 3)
return false;
if(sum(arr+1, x-arr[0], n-1, index + 1))
return true;
return sum(arr+1, x, n-1, index);
}
The top call starts with index = 0. Basically I'm trying to see if there is a triple that sums to a given value x.
Am I missing something?
First of all, T(n) = 2T(n-1) + Const would make T(n) be in O(2^n), not O(n). This would be the runtime if you didn't have the index == 3 stopping condition. But this stopping condition decreases the runtime significantly.
One way to find the time complexity is to count the number of leaves in the recursion tree (i.e. number of times a stop condition was reached). Each leaf with index == 3 corresponds to a choice of 3 out of n elements, so there are C(n, 3) such nodes. Leaves with n == 0 and index < 3 corresponds to a choice of 0, 1, or 2 elements, i.e. C(n, 0) + C(n, 1) + C(n, 2). The total number of leaves is thus O(n^3).
Since the number of inner nodes (calls which do not reach a stop condition and thus make recursive calls) is about equal to the number of leaves, and each call does O(1) work not including the recursive calls, the total runtime is O(n^3).
Another way to get the same result is to consider T(n, index):
T(n, 3) = C = O(1)
T(n, 2) = T(n-1, 3) + T(n-1, 2) + C = O(n)
T(n, 1) = T(n-1, 2) + T(n-1, 1) + C = O(n^2)
T(n, 0) = T(n-1, 1) + T(n-1, 0) + C = O(n^3)
Given that the top-level call is assumed to be made with index == 0 (from comments), the algorithm is O(n3). Ignore the details of the implementation, and consider more abstractly what it is doing:
It performs a linear scan over array arr, where
for each element e, it performs a linear scan over the tail of arr starting after e, where
for each element f, it performs a linear scan over the tail of arr starting after f, where
for each element g, it checks whether e + f + g == x
The boundary case is the one in which no triplet of elements sums to x, and in that case the procedure does not end until all the scans are complete. As should be clear from that description, the recursion is equivalent to a triply-nested loop.
Related
I need to find the time and space complexity of f3.
I think that g has space complexity of log(n), so for the time complexity, but I am not really sure how I find the time and space complexity of f3 because the calling for g is inside the for commend, does it mean the g is being called every time to check if g(i) < n?
int g(int n)
{
if (n <= 1)
return 1;
return g(n / 2) + 1;
}
int f3(int n)
{
int counter = 0;
for (int i = 0; g(i) < n; ++i)
++counter;
return counter;
}
In short:
Time complexity of f3(n) = O(2^n)
Space complexity of f3(n) = O(n)
Space and Time complexity of g(n) = O(log(n))
Note: (here all log that I refer are log base2 link and all notations are in Big O notation)
Details:
The function "g()" returns floor(log(n))+1. The loop in function "f3()" cotinues until the function 'g()' returns n. For g(i) to return 'n', i needs to be '2^(n-1)'.
In order to terminate the loop in "f3()", 'i' needs to reach 2^(n-1). So 'g()' is called 2^(n-1) times.
So Time complexity of "f3()" = 2^(n-1) x (time complexity of g()) = 2^n x (log n) = O(2^n)
Largest memory used will be during the last call of 'g(i)' where i==2^(n-1).
Therefore space complexity of "f3()" = log(2^(n-1)) = O(n)
As g(n) will run in Theta(log(n)) and each time adds 1 to the final result, the final value of g(i) will be \ceil{log(i)} + 1. On the other hand, the loop inside f3 will run while g(i) < n. It means the loop will iterate up to 2^n. Hence, f3 will run 2^n times. Hence, the time complexity of f3(n) = sum_{i=1}^{2^n} log(i) = log((2^n)!) = \Theta(n * 2^n) (as log((2^n)!) ~ (2^n) log(2^n)).
About space complexity, the maximum depth of g(i), will be when i = 2^n, which is n (n recursive calls). Hence, the space complexity of f3 will be \Theta(n).
This question already has answers here:
Finding three elements in an array whose sum is closest to a given number
(15 answers)
O(NlogN) finding 3 numbers that have a sum of any arbitrary T in an array
(7 answers)
Closed 5 years ago.
a little stuck finding an efficient algorithm for the following problem. The algo has to decide if there are 3 elements a,b and c in an array so that a+b+c is equal to a given number z.
The naive way would be to try out the combinations, of course, but asymptotically the time needed would be too large.
For finding a and b in an array so that the sum is z is much easier. Sort the given array in ascending order and check for every element if z-a exists. But I'm not sure how I'd implement it in the 3 element problem and what time would be needed.
Any help is much appreciated!
Edit: a,b,c and z are integers.
The approach is very similar to finding a and b with sum z.
First sort the array. And then fix a at position i and check if you have sumz-a in the limits i + 1 to n
Since you have a O(n) algorithm to check if a sum z exist with a and b. We only extend it to fix a and check if two other variable can be used to produce the sum. Giving a overall run time of O(n^2)
From here
// returns true if there is triplet with sum equal
// to 'sum' present in A[]. Also, prints the triplet
bool find3Numbers(int A[], int arr_size, int sum)
{
int l, r;
/* Sort the elements */
sort(A, A+arr_size);
/* Now fix the first element one by one and find the
other two elements */
for (int i=0; i<arr_size-2; i++)
{
// To find the other two elements, start two index
// variables from two corners of the array and move
// them toward each other
l = i + 1; // index of the first element in the
// remaining elements
r = arr_size-1; // index of the last element
while (l < r)
{
if( A[i] + A[l] + A[r] == sum)
{
printf("Triplet is %d, %d, %d", A[i],
A[l], A[r]);
return true;
}
else if (A[i] + A[l] + A[r] < sum)
l++;
else // A[i] + A[l] + A[r] > sum
r--;
}
}
// If we reach here, then no triplet was found
return false;
}
I suppose I should've written a short comment as an answer, but I don't have enough reputation for it ... So here goes nothing!
The best algorithm I can come up with right now is O(n^2), to explain this algorithm better we shall start with the a+b = z in O(n) case (or O(nlgn) if it wasn't sorted)
First of all, iterate {a}, and find {b} such that a+b = z. Naively if you iterate all b this would cost O(n) per {a}, leading to a O(n^2) solution. However, if you iterate {a} increasingly, the value of {b} must be strictly decreasing. We can make use of this information to reduce the time complexity as in this code:
for a = first element, b = last element; a != last; a = next a
while ( ( b != first element ) and (a + b > z) )
b = previous elemnet of b
if a + b == z
return true
Note that {b} only goes through the whole list once throughout loop, so it has a complexity of amortized O(n).
Now we can apply this principle back to the original problem, we could iterate through {a}, and apply this O(n) algorithm to {b, c} to find {z-a}, the total complexity is O(n*n = n^2).
Hopefully there is a solution with a lower complexity, I don't think O(n^2) is impressive but I just can't come up with a better one.
We are given a sorted array A[1..n] of n integers. We say an element x E A is rare if it occurs
in A strictly less than n/10 times. That is, x is rare if there is some index 1 <= i <= n such that
A(i) = x, and there are strictly less than n/10 distinct indices j for which A(j) = x. Our goal
is to find a rare element, or output that A contains no rare elements.
Input: A sorted array A[1..n] of n integers.
Output: A rare element x E A, or the output “No rare element exists in A.”
Is there an O(log n) time algorithm for the rare element problem? What is it?
T(n) = 10 T(n/10) + O(1) gives O(n) time which is not good enough for me.
Yes, it's possible to do it in O(log n). I assume, that you already have this array in memory. Otherwise it's impossible to do it faster than in O(n), because you need to read array at least.
Let's say that step is the biggest integer that is less than n/10. If step is equal to zero then we don't have rare elements obviously.
Consider the following algorithm:
int start = 1;
while (true) {
if (n - start + 1 <= step) {
OutputRare(A[start]); Exit;
}
int next_index = start + step;
if (A[start] != A[next_index]) {
OutputRare(A[start); Exit;
}
// Here we need to find the smallest index starting from start with
// element that is not equal to A[start]. If such element does not
// exist function returns -1.
next_index = FindFirstNonEqual(A[start], start);
if (next_index == -1) {
// There is no rare elements
Exit;
}
start = next_index;
}
This algorithm either returns rare element, or increases start by at least step. Which means that it will increase start ~10 times (because every step is about n/10). FindFirstNonEqual can be implemented using binary search, which means that total complexity is O(10log n) = O(log n).
So I had to insert N elements in random order into a size-N array, but I am not sure about the time complexity of the program
the program is basically:
for (i = 0 -> n-1){
index = random (0, n); (n is exclusive)
while (array[index] != null)
index = random (0, n);
array[index] = n
}
Here is my assumption: a normal insertion of N numbers is of course strictly N, but how much cost will the collision from random positions cost? For each n, its collision rate increases like 0, 1/n, 2/n .... n-1/n, so expected number of insertions attempts will be 1, 2, 3 .. n-1, this is O(n), so total time complexity will be O(n^2), so is this the average cost? but wow this is really bad, am I right?
So what will happen if I do a linear search instead of keep trying to generate random numbers? Its worst case will obviously be O(n^2>, but I don't know how to analyze its average case, which depends on average input distribution?
First consider the inner loop. When do we expect to have our first success (find an open position) when there are i values already in the array? For this we use the geometric distribution:
Pr(X = k) = (1-p)^{k-1} p
Where p is the probability of success for an attempt.
Here p is the probability that the array index is not already filled.
There are i filled positions so p = (1 - (i/n)) = ((n - i)/n).
From the wiki, the expectation for the geometric distribution is 1/p = 1 / ((n-i)/n) = n/(n-i).
Therefore, we should expect to make (n / (n - i)) attempts in the inner loop when there are i items in the array.
To fill the array, we insert a new value when the array has i=0..n-1 items in it. The amount of attempts we expect to make overall is the sum:
sum_{i=0,n-1} n/(n-i)
= n * sum_{i=0,n-1}(1/(n-i))
= n * sum_{i=0,n-1}(1/(n-i))
= n * (1/n + 1/(n-1) + ... + 1/1)
= n * (1/1 + ... + 1/(n-1) + 1/n)
= n * sum_{i=1,n}(1/i)
Which is n times the nth harmonic number and is approximately ln(n) + gamma, where gamma is a constant. So overall, the number of attempts is approximately n * (ln(n) + gamma), which is O(nlog n). Remember that this is only the expectation and there is no true upper bound since the inner loop is random; it may never find an open spot.
The expected number of insertions attempt at step i is
sum_{t=0}^infinity (1-i/n)^t * (n-i)/n * t
= (n-i)/n * i/n * (1-i/n)^{-2}
= i/(n-i)
Summing over i you get
sum_{i=0}^{n-1} i/(n-1)
>= sum_{i=n/2}^n i / (n-i)
>= n/2 sum_{x=1}^n/2 1/x
>= n/2 * log(n) + O(n)
And
sum_{i=0}^{n-1} i/(n-i)
<= n * sum _{x=1}^n 1/x
<= n * log(n) + O(n)
So you get exactly n*log(n) as an asymptotic complexity. Which is not as bad as you feared.
About doing a linear search, I don't know how you would do it while keeping the array random. If you really want an efficient algorithm to shuffle your array, you should check out Fisher-Yates shuffle.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How to find the kth smallest element in the union of two sorted arrays?
This is a question one of my friends told me he was asked while interviewing, I've been thinking about a solution.
Sublinear time implies logarithmic to me, so perhaps some kind of divide and conquer method. For simplicity, let's say both arrays are the same size and that all elements are unique
I think this is two concurrent binary searches on the subarrays A[0..n-1] and B[0..n-1], which is O(log n).
Given sorted arrays, you know that the nth largest will appear somewhere before or at A[n-1] if it is in array A, or B[n-1] if it is in array B
Consider item at index a in A and item at index b in B.
Perform binary search as follows (pretty rough pseudocode, not taking in account 'one-off' problems):
If a + b > n, then reduce the search set
if A[a] > B[b] then b = b / 2, else a = a / 2
If a + b < n, then increase the search set
if A[a] > B[b] then b = 3/2 * b, else a = 3/2 * a (halfway between a and previous a)
If a + b = n then the nth largest is max(A[a], B[b])
I believe worst case O(ln n), but in any case definitely sublinear.
I believe that you can solve this problem using a variant on binary search. The intuition behind this algorithm is as follows. Let the two arrays be A and B and let's assume for the sake of simplicity that they're the same size (this isn't necessary, as you'll see). For each array, we can construct parallel arrays Ac and Bc such that for each index i, Ac[i] is the number of elements in the two arrays that are no larger than A[i] and Bc[i] is the number of elements in the two arrays that are no larger than B[i]. If we could construct these arrays efficiently, then we could find the kth smallest element efficiently by doing binary searches on both Ac and Bc to find the value k. The corresponding entry of A or B for that entry is then the kth largest element. The binary search is valid because the two arrays Ac and Bc are sorted, which I think you can convince yourself of pretty easily.
Of course, this solution doesn't work in sublinear time because it takes O(n) time to construct the arrays Ac and Bc. The question then is - is there some way that we can implicitly construct these arrays? That is, can we determine the values in these arrays without necessarily constructing each element? I think that the answer is yes, using this algorithm. Let's begin by searching array A to see if it has the kth smallest value. We know for a fact that the kth smallest value can't appear in the array in array A after position k (assuming all the elements are distinct). So let's focus just on the the first k elements of array A. We'll do a binary search over these values as follows. Start at position k/2; this is the k/2th smallest element in array A. Now do a binary search in array B to find the largest value in B smaller than this value and look at its position in the array; this is the number of elements in B smaller than the current value. If we add up the position of the elements in A and B, we have the total number of elements in the two arrays smaller than the current element. If this is exactly k, we're done. If this is less than k, then we recurse in the upper half of the first k elements of A, and if this is greater than k we recurse in the lower half of the first elements of k, etc. Eventually, we'll either find that the kth largest element is in array A, in which case we're done. Otherwise, repeat this process on array B.
The runtime for this algorithm is as follows. The search of array A does a binary search over k elements, which takes O(lg k) iterations. Each iteration costs O(lg n), since we have to do a binary search in B. This means that the total time for this search is O(lg k lg n). The time to do this in array B is the same, so the net runtime for the algorithm is O(lg k lg n) = O(lg2 n) = o(n), which is sublinear.
This is quite similar answer to Kirk's.
Let Find( nth, A, B ) be function that returns nth number, and |A| + |B| >= n. This is simple pseudo code without checking if one of array is small, less than 3 elements. In case of small array one or 2 binary searches in larger array is enough to find needed element.
Find( nth, A, B )
If A.last() <= B.first():
return B[nth - A.size()]
If B.last() <= A.first():
return A[nth - B.size()]
Let a and b indexes of middle elements of A and B
Assume that A[a] <= B[b] (if not swap arrays)
if nth <= a + b:
return Find( nth, A, B.first_half(b) )
return Find( nth - a, A.second_half(a), B )
It is log(|A|) + log(|B|), and because input arrays can be made to have n elements each it is log(n) complexity.
int[] a = new int[] { 11, 9, 7, 5, 3 };
int[] b = new int[] { 12, 10, 8, 6, 4 };
int n = 7;
int result = 0;
if (n > (a.Length + b.Length))
throw new Exception("n is greater than a.Length + b.Length");
else if (n < (a.Length + b.Length) / 2)
{
int ai = 0;
int bi = 0;
for (int i = n; i > 0; i--)
{
// find the highest from a or b
if (ai < a.Length)
{
if (bi < b.Length)
{
if (a[ai] > b[bi])
{
result = a[ai];
ai++;
}
else
{
result = b[bi];
bi++;
}
}
else
{
result = a[ai];
ai++;
}
}
else
{
if (bi < b.Length)
{
result = b[bi];
bi++;
}
else
{
// error, n is greater than a.Length + b.Length
}
}
}
}
else
{
// go in reverse
int ai = a.Length - 1;
int bi = b.Length - 1;
for (int i = a.Length + b.Length - n; i >= 0; i--)
{
// find the lowset from a or b
if (ai >= 0)
{
if (bi >= 0)
{
if (a[ai] < b[bi])
{
result = a[ai];
ai--;
}
else
{
result = b[bi];
bi--;
}
}
else
{
result = a[ai];
ai--;
}
}
else
{
if (bi >= 0)
{
result = b[bi];
bi--;
}
else
{
// error, n is greater than a.Length + b.Length
}
}
}
}
Console.WriteLine("{0} th highest = {1}", n, result);
Sublinear of what though? You can't have an algorithm that doesn't check at least n elements, even verifying a solution would require checking that many. But the size of the problem here should surely mean the size of the arrays, so an algorithm that only checks n elements is sublinear.
So I think there's no trick here, start with the list with the smaller starting element and advance until you either:
Reach the nth element, and you're done.
Find the next element is bigger than the next element in the other list, at which point you switch to the other list.
Run out of elements and switch.