Showing that a recurrence relation is O(n log n) - algorithm

T (n) = T (xn) + T ((1 − x)n) + n = O(n log n)
where x is a constant in the range 0 < x < 1. Is the asymptotic complexity the same when x = 0.5, 0.1 and 0.001?
What happens to the constant hidden in the O() notation. Use Substitution Method.
I'm trying to use the example on ~page 15 but I find it weird that in that example the logs change from default base to base 2.
I also do not really understand why it needed to be simplified so much just so as to remove cnlog2n from the left side, could that not be done in the first step and the left side would just have "stuff-cnlog2n<=0" then evaulated for any c and n like so?
From what I tried it could not prove that T(n)=O(n)

Well, if you break this up into a tree using Master's theorem, then this will have a constant "amount" to calculate each time. You know this because x + 1 - x = 1.
Thus, the time depends on the level of the tree, which is logarithmic since the pieces are reducing each time by some constant amount. Since you do O(n) calcs each level, your overall complexity is O( n log n ).
I expect this will be a little more complicated to "prove". Remember that it doesn't matter what base your logs are in, they're all just some constant factor. Refer to logarithmic relations for this.
PS: Looks like homework. Think harder yourself!

This seems to me exactly the recurrence equation for the average case in Quicksort.
You should look at CLRS explanation of "Balanced Partitioning".

but I find it weird that in that example the logs change from default base to base 2
That is indeed weird. Simple fact is, that it's easier to prove with base 2, than with base unknown x. For example, log(2n) = 1+log(n) in base 2, that is a bit easier. You don't have to use base 2, you can pick any base you want, or use base x. To be absolutely correct the Induction Hypothesis must have the base in it: T(K) <= c K log_2(K). You can't change the IH later on, so what is happening now is not correct in a strict sense. You're free to pick any IH you like, so, just pick one that makes the prove easier: in this case logs with base 2.
the left side would just have "stuff-cnlog2n<=0" then evaulated for any c and n
What do you mean with 'evaluated for any c and n'? stuff-cnlog2n<=0 is correct, but how do you prove that there is a c so that it holds for all n? Okay, c=2 is a good guess. To prove it like that in WolframAlpha, you need to do stuff <= 0 where c=2, n=1 OK!, stuff <=0 where c=2, n=2OK!, stuff <= 0 where c=2, n=3OK!, ..., etc taking n all the way to infinity. Hmm, it will take you an infinite amount of time to check all of them... The only practical way (I can think of right now) for solving this is to simplify stuff-cnlog2n<=0. Or maybe you prefer this argument: you don't have WolframAlpha at your exam, so you must simplify.

Related

What is meant by d=θ(N) in terms of a d-heap where N is the number of elements?

Problem I want to solve: if you have to do M percolations and N deleteMins on a d-heap that initially has N elements. What is the running time for d=θ(N)?
I am confused by what d=θ(N) means. θ is supposed to represent average case running time, but in this case it is used to represent the value of d.
My question: I am assuming this mean d = N so that would mean the actual heap is simply one root with all other elements connected to that one root. Is my interpretation accurate?
Big-theta notation is often used for asymptotic running time, but it's just a relationship between values and functions, and can be used in other contexts as well.
d=θ(N) means that there are constants a and b such that, when N is big enough, aN < d < bN
Obviously, you can't have d > N in this case, since the heap only has N elements, but that a constant can be arbitrarily small. You could have d = 0.1N, for example.
The phrasing of the question suggests that the asymptotic running time will be the same no matter what these constants a and b are, which is a pretty big hint as to what the answer is. You can assume that d = N, for example, and then check to make sure you get the same answer when d = 0.1N.

O(log n) clarification

There are plenty of questions around O(log n) and what it actually means, not trying to open that up again.
However on this particular answer https://stackoverflow.com/a/36877205/10894153, this image makes no sense to me:
That being said, seeing as that answer has over 100 up votes votes and has been up for more than 2 years and no comments to indicate anything might be wrong, I assume I am misunderstanding something, hence asking here for clarification (and I can't post comments because of low reputation).
Mainly, I don't understand why O(log(n)) is 10 when n == 1024. Shouldn't this be 32, seeing as 32^2 = 1024?
Clearly this has an effect on O(n * log(n)) as well, but just need to understand why O(log(1024)) = 10
The table is correct, except that the headings could be misleading because the values below them correspond to the expressions inside the big-O, rather than to the big-O themselves. But that is understandable because O-notations have the meaning of disregarding multiplicative constants.
Something similar happens with log(n). The log notation has also the meaning of disregarding the base of the logarithmic function. But that's fine in this context because:
log_b(n) = log_2(n)/log_2(b) ; see below why this is true
meaning that the function log_b() is just a multiplicative constant away, namely 1/log_2(b), from log_2().
And since the table is purposely emphasizing the fact that the big-O notation disregards multiplicative constants, it is fine to assume that all logs in it are 2-based.
In particular, O(log(1024)) can be interpreted as log_2(1024) which is nothing but 10 (because 2^10 = 1024).
To verify the equation above, we need to check that
log_2(n) = log_2(b)log_b(n)
By the definition of log we have to see that n is 2 to the righ-hand-side, i.e.,
n = 2^{log_2(b)log_b(n)}
but the right hand side is
{2^{log_2(b)}}^{log_b(n)} = b^{log_b(n)} = n
again by definition (applied twice).

Working with small probabilities, via logs

Source: Google Code Jam. https://code.google.com/codejam/contest/10224486/dashboard#s=a&a=1
We're asked to calculate Prob(K successes from N trials) where each of the N trials has a known success probability of p_n.
Some Analysis and thoughts on the problem are given after the Code Jam.
They observe that evaluating all possible outcomes of your N trials would take you an exponential time in N, so instead they provide a nice "dynamic programming" style solution that's O(N^2).
Let P(p#q) = Prob(p Successes after the first q Trials)
Then observe the fact that:
Prob(p#q) = Prob(qth trial succeeds)*P(p-1#q-1) + Prob(qth trial fails)*P(p#q-1)
Now we can build up a table of P(i#j) where i<=j, for i = 1...N
That's all lovely - I follow all of this and could implement it.
Then as the last comment, they say:
In practice, in problems like this, one should store the logarithms of
probabilities instead of the actual values, which can become small
enough for floating-point precision errors to matter.
I think I broadly understand the point they're trying to make, but I specifically can't figure out how to use this suggestion.
Taking the above equation, and substuting in some lettered variables:
P = A*B + C*D
If we want to work in Log Space, then we have:
Log(P) = Log(A*B + C*D),
where we have recursively pre-computed Log(B) and Log(D), and A & B are known, easily-handled decimals.
But I don't see any way to calculate Log(P) without just doing e^(Log(B)), etc. which feels like it would defeat to point of working in log space`?
Does anyone understand in better detail what I'm supposed to be doing?
Starting from the initial relation:
P = A⋅B + C⋅D
Due to its symmetry we can assume that B is larger than D, without loss of generality.
The following processing is useful:
log(P) = log(A⋅B + C⋅D) = log(A⋅elog(B) + C⋅elog(D)) = log(elog(B)⋅(A + C⋅elog(D) - log(B))
log(P) = log(B) + log(A + C⋅elog(D) - log(B)).
This is useful because, in this case, log(B) and log(D) are both negative numbers (logarithms of some probabilities). It was assumed that B is larger than D, thus its log is closer to zero. Therefore log(D) - log(B) is still negative, but not as negative as log(D).
So now, instead of needing to perform exponentiation of log(B) and log(D) separately, we only need to perform exponentiation of log(D) - log(B), which is a mildly negative number. So the above processing leads to better numerical behavior than using logarithms and applying exponentiation in the trivial way, or, equivalently, than not using logarithms at all.

Order of growth rate in increasing order

Arrange the following functions in increasing order of growth rate
(with g(n) following f(n) in your list if and only if f(n)=O(g(n))).
a)2^log(n)
b)2^2log(n)
c)n^5/2
d)2^n^2
e)n^2 log(n)
So i think answer is in increasing order is
CEDAB
is it correct? i have confusion in option A and B.
i think option A should be at first place.. less one i mean so please help how to solve this.
This question I faced in algorithm course part 1 assignment (Coursera) .
Firstly, any positive power of n is always greater than log n, so E comes before C, not after.
Also, D comes after every other function, as either interpretation of 2^n^2 (could be 2^(n^2) or (2^n)^2 = 2^(2n); I could be wrong in ignoring BIDMAS though...) are exponentials of n itself.
Taking log to be base a, some arbitrary constant:
a)
b)
Thus, unfortunately, the actual order depends of the value of a, e.g. if the value of
is greater than 2, then A comes after E, otherwise before. Curiously the base of the log term in E is irrelevant (it still maintains its place).
The answer is aecbd
The easiest way to see why is to create a table with different values of n and compare amongst them. But some intuition:
a grows lesser than any others, specially c because of the log term in the power as opposed to the term itself
e is a with a n**2 term multiplied in, which is better than it being in an exponent
b is a double exponent, but still better than a quadratic power
d is the obvious worst because it grows exponentially with a quadratic power!

Complexity class

Assume that methods m1 and m2 are static void and compute the same result by processing an argument of type Object[]. Empirically we find that m1 -> T(N) = 100N and m2 -> T(N) = 10Nlog2N where the times are in microseconds. For what size inputs is it better to use m1 and m2?
So I would use m1 for big numbers while I would use m2 for small numbers right? just checking the answers.
You're looking for the value of N > 0 such that 100N > 10N log2 N, so that's just an algebra problem. Divide both sides by 10N and you get 10 > log2 N, i.e., N < 2**10, i.e. N < 1024. Not that hard!-)
Well, log2N is going to hit 10 when N is 1024, so according to the formulae you've given us, you would use the second one for N <= 1024 and the first for N >= 1024. (What you do "on the boundary" doesn't matter - they'll be equal.)
However, from a practical point of view you should quite possibly pick one and maintain just that one. Do you expect very large inputs, or lots of small inputs? Is this definitely a bottleneck in your code? Which is the simpler algorithm?
There's a lot more to deciding which algorithm is the best than just which is the fastest for a given input. I would rather maintain a simple algorithm which runs slightly slower than a fast but insanely complicated one.
Look at this: http://www.wolframalpha.com/input/?i=plot+100*n+and+plot+10*n*log2(n)
I haven't figured out yet how to modify the scale though. In any case, for future reference.

Resources