complexity on recursive Big-O - recursion

I have a Computer Science Midterm tomorrow and I need help determining the complexity of these recursive functions. I know how to solve simple cases, but I am still trying to learn how to solve these harder cases. Any help would be much appreciated and would greatly help in my studies, Thank you!
fonction F(n)
if n == 0
return 1
else
return F(n-1) * n
fonction UniqueElements(A[0..n-1])
for i=0 to i <= n-2 do
for j=i+1 to j <= n-1 do
if A[i] == A[j]
return false
return true
fonction BinRec(n)
if n == 1
return 1
else
return BinRec(floor(n/2)) + 1

For hands on learning, you can plug the functions into a program, and test their worst case scenario performance.
When trying to calculate O by hand, here are some things to remember
The +, -, *, and / offsets can be ignored. So 1 to n+5 and 1 to 5n is considered equivalent to 1 to n.
Also, Only the highest order of magnitude counts, so for O 2^n + n^2 + n, 2^n grows the fastest, so it is equivalent to O 2^n
With recursive functions, you are looking at how many times the function is called in the method (the split count) and how much it needs to be called (the depth, usually is equal to list length). So the final O will be depth_count^split_count
With loops, each nested loop multiplies to the one it's in, and sequential loops add, so (1-n){(1-n){}} (1-n){} is (n * n) + n) => n^2 + n =(only highest growth counts)> n^2
PRACTICE! You will need to practice to get the hang of the gatchas of growth rate and how control flows interact. (so do online practice quizs)
function F(n){
count++
if (n == 0)
return 1
else
return F(n-1) * n
}
function UniqueElements(A){
for (var i=0 ; i <= A.length-2; i++){
for (var j=i+1;j <= A.length-1; j++){
if (A[i] == A[j]){
return false
}
}
}
return true
}
function BinRec(n) {
count++
if (n == 1)
return 1
else
return BinRec(Math.floor(n/2)) + 1
}
count = 0;
console.log(F(10));
console.log(count);
count = 0;
console.log(UniqueElements([1,2,3,5]));
console.log(count);
count = 0;
console.log(BinRec(40));
console.log(count);

Related

How do I calculate the time complexity of this recursive function which halves the input value or halves it and then adds the input value?

I am having difficulties determining the time complexity of the code below:
int func(int n) { // n > 0
if (n < 2) {
return 1;
} else if (n % 2 == 0) {
return func(n / 3);
} else {
return func(n / 3) + n;
}
}
I have attempted to approach this question using Master Theorem, so I have tried to break it down into:
n = size of input
a = number of sub-problems in the recursion = 3
n/b = size of each sub-problem
f(n) = cost of the work done outside the recursive call
However, I am struggling to understand how to determine the size of each sub-problem and f(n) - the cost of the work done outside the recursive call. At the moment I am just assuming that we take the greater time complexity of the if/else statement so the time complexity would be O(logn).
Also, does the '+ n' in the else statement affect the time complexity of this function?
Any help to understand this would be greatly appreciated!

How to find the time complexity of the below function?

I am facing difficulty to figure out the time complexity of this below function. Please help to find how to solve this question?
int sumOfDigits(int n){
int sum;`
if(n < 10){
return n;
}
sum = (n % 10) + sumOfDigits(n / 10);
return sum;
}
The function considers each digit of a number n and returns the sum of them.
The number of iterations is ⌊log10(n)⌋ + 1 and depends on the number of digits of n. Therefore, T(n) = O(log n)

Sum of combinations of numbers

I want to solve a mathematical problem in a fastest possible way.
I have a set of natural numbers between 1 to n, for example {1,2,3,4,n=5} and I want to calculate a formula like this:
s = 1*2*3*4+1*2*3*5+1*2*4*5+1*3*4*5+2*3*4*5
as you can see, each element in the sum is a multiplications of n-1 numbers in the set. For example in (1*2*3*4), 5 is excluded and in (1*2*3*5), 4 is excluded. I know some of the multiplications are repeated, for example (1*2) is repeated in 3 of the multiplications. How can I solve this problem with least number of multiplications.
Sorry for bad English.
Thanks.
Here is a way that does not "cheat" by replacing multiplication with repeated addition or by using division. The idea is to replace your expression with
1*2*3*4 + 5*(1*2*3 + 4*(1*2 + 3*(1 + 2)))
This used 9 multiplications for the numbers 1 through 5. In general I think the multiplication count would be one less than the (n-1)th triangular number, n * (n - 1) / 2 - 1. Here is Python code that stores intermediate factorial values to reduce the number of multiplications to just 6, or in general 2 * n - 4, and the addition count to the same (but half of them are just adding 1):
def f(n):
fact = 1
term = 2
sum = 3
for j in range(2, n):
fact *= j
term = (j + 1) * sum
sum = fact + term
return sum
The only way to find which algorithm is the fastest is to code all of them in one language, and run each using a timer.
The following would be the most straightforward answer.
def f(n):
result = 0
nList = [i+1 for i in range(n)]
for i in range(len(nList)):
result += reduce(lambda x, y: x*y,(nList[:i]+nList[i+1:]))
return result
Walkthrough - use the reduce function to multiply all list's of length n-1 and add to the variable result.
If you just want to minimise the number of multiplications, you can replace all the multiplications by additions, like this:
// Compute 1*2*…*n
mult_all(n):
if n = 1
return 1
res = 0
// by adding 1*2*…*(n-1) an entirety of n times
for i = 1 to n do
res += mult_all(n-1)
return res
// Compute sum of 1*2*…*(i-1)*(i+1)*…*n
sum_of_mult_all_but_one(n):
if n = 1
return 0
// by computing 1*2*…*(n-1) + (sum 1*2*…*(i-1)*(i+1)*…*(n-1))*n
res = mult_all(n-1)
for i = 1 to n do
res += sum_of_mult_all_but_one(n-1)
return res
Here is an answer that would work with javascript. It is not the fastest way because it is not optimized, but it should work if you want to just find the answer.
function combo(n){
var mult = 1;
var sum = 0;
for (var i = 1; i <= n; i++){
mult = 1;
for (var j = 1; j<= n; j++){
if(j != i){
mult = mult*j;
}
}
sum += mult;
}
return (sum);
}
alert(combo(n));

How to calculate the complexity of time and memory

I have the following code
public int X(int n)
{
if (n == 0)
return 0;
if (n == 1)
return 1;
else
return (X(n- 1) + X(n- 2));
}
I want to calculate the complexity of time and memory of this code
My code consists of a constant checking if (n == 0) return 0; so this will take a constant time assume c so we have either c or c or the calculation of the recursion functions which I can't calculate
Can anyone help me in this?
To calculate the value of X(n), you are calculating X(n-1) and X(n-2)
So T(n) = T(n-1) + T(n-2);
T(0) = 1
T(1) = 1
which is exponential O(2^n)
If you want detailed proof of how it will be O(2^n), check here.
Space complexity is linear.
(Just to be precise, If you consider the stack space taken for recursion, it's O(n))

Math Problem: Scale a graph so that it matches another

I have 2 tables of values and want to scale the first one so that it matches the 2nd one as good as possible. Both have the same length. If both are drawn as graphs in a diagram they should be as close to each other as possible. But I do not want quadratic, but simple linear weights.
My problem is, that I have no idea how to actually compute the best scaling factor because of the Abs function.
Some pseudocode:
//given:
float[] table1= ...;
float[] table2= ...;
//wanted:
float factor= ???; // I have no idea how to compute this
float remainingDifference=0;
for(int i=0; i<length; i++)
{
float scaledValue=table1[i] * factor;
//Sum up the differences. I use the Abs function because negative differences are differences too.
remainingDifference += Abs(scaledValue - table2[i]);
}
I want to compute the scaling factor so that the remainingDifference is minimal.
Simple linear weights is hard like you said.
a_n = first sequence
b_n = second sequence
c = scaling factor
Your residual function is (sums are from i=1 to N, the number of points):
SUM( |a_i - c*b_i| )
Taking the derivative with respect to c yields:
d/dc SUM( |a_i - c*b_i| )
= SUM( b_i * (a_i - c*b_i)/|a_i - c*b_i| )
Setting to 0 and solving for c is hard. I don't think there's an analytic way of doing that. You may want to try https://math.stackexchange.com/ to see if they have any bright ideas.
However if you work with quadratic weights, it becomes significantly simpler:
d/dc SUM( (a_i - c*b_i)^2 )
= SUM( 2*(a_i - c*b_i)* -c )
= -2c * SUM( a_i - c*b_i ) = 0
=> SUM(a_i) - c*SUM(b_i) = 0
=> c = SUM(a_i) / SUM(b_i)
I strongly suggest the latter approach if you can.
I would suggest trying some sort of variant on Newton Raphson.
Construct a function Diff(k) that looks at the difference in area between your two graphs between fixed markers A and B.
mathematically I guess it would be integral ( x = A to B ){ f(x) - k * g(x) }dx
anyway realistically you could just subtract the values,
like if you range from X = -10 to 10, and you have a data point for f(i) and g(i) on each integer i in [-10, 10], (ie 21 datapoints )
then you just sum( i = -10 to 10 ){ f(i) - k * g(i) }
basically you would expect this function to look like a parabola -- there will be an optimum k, and deviating slightly from it in either direction will increase the overall area difference
and the bigger the difference, you would expect the bigger the gap
so, this should be a pretty smooth function ( if you have a lot of data points )
so you want to minimise Diff(k)
so you want to find whether derivative ie d/dk Diff(k) = 0
so just do Newton Raphson on this new function D'(k)
kick it off at k=1 and it should zone in on a solution pretty fast
that's probably going to give you an optimal computation time
if you want something simpler, just start with some k1 and k2 that are either side of 0
so say Diff(1.5) = -3 and Diff(2.9) = 7
so then you would pick a k say 3/10 of the way (10 = 7 - -3) between 1.5 and 2.9
and depending on whether that yields a positive or negative value, use it as the new k1 or k2, rinse and repeat
In case anyone stumbles upon this in the future, here is some code (c++)
The trick is to first sort the samples by the scaling factor that would result in the best fit for the 2 samples each. Then start at both ends iterate to the factor that results in the minimum absolute deviation (L1-norm).
Everything except for the sort has a linear run time => Runtime is O(n*log n)
/*
* Find x so that the sum over std::abs(pA[i]-pB[i]*x) from i=0 to (n-1) is minimal
* Then return x
*/
float linearFit(const float* pA, const float* pB, int n)
{
/*
* Algebraic solution is not possible for the general case
* => iterative algorithm
*/
if (n < 0)
throw "linearFit has invalid argument: expected n >= 0";
if (n == 0)
return 0;//If there is nothing to fit, any factor is a perfect fit (sum is always 0)
if (n == 1)
return pA[0] / pB[0];//return x so that pA[0] = pB[0]*x
//If you don't like this , use a std::vector :P
std::unique_ptr<float[]> targetValues_(new float[n]);
std::unique_ptr<int[]> indices_(new int[n]);
//Get proper pointers:
float* targetValues = targetValues_.get();//The value for x that would cause pA[i] = pB[i]*x
int* indices = indices_.get(); //Indices of useful (not nan and not infinity) target values
//The code above guarantees n > 1, so it is safe to get these pointers:
int m = 0;//Number of useful target values
for (int i = 0; i < n; i++)
{
float a = pA[i];
float b = pB[i];
float targetValue = a / b;
targetValues[i] = targetValue;
if (std::isfinite(targetValue))
{
indices[m++] = i;
}
}
if (m <= 0)
return 0;
if (m == 1)
return targetValues[indices[0]];//If there is only one target value, then it has to be the best one.
//sort the indices by target value
std::sort(indices, indices + m, [&](int ia, int ib){
return targetValues[ia] < targetValues[ib];
});
//Start from the extremes and meet at the optimal solution somewhere in the middle:
int l = 0;
int r = m - 1;
// m >= 2 is guaranteed => l > r
float penaltyFactorL = std::abs(pB[indices[l]]);
float penaltyFactorR = std::abs(pB[indices[r]]);
while (l < r)
{
if (l == r - 1 && penaltyFactorL == penaltyFactorR)
{
break;
}
if (penaltyFactorL < penaltyFactorR)
{
l++;
if (l < r)
{
penaltyFactorL += std::abs(pB[indices[l]]);
}
}
else
{
r--;
if (l < r)
{
penaltyFactorR += std::abs(pB[indices[r]]);
}
}
}
//return the best target value
if (l == r)
return targetValues[indices[l]];
else
return (targetValues[indices[l]] + targetValues[indices[r]])*0.5;
}

Resources