Solve using either master theorem or by expansion - algorithm

I have two questions, which I have trying but unable to figure them out.
1) ๐‘‡(๐‘›) = ๐‘‡(๐‘› โˆ’ 1) + ๐‘›^4
2) ๐‘‡(๐‘›) = 2๐‘‡ (๐‘›/2) + ๐‘› lg ๐‘›
For first one, I am assuming substitution (am I correct?), and got kb + T(n-k). Pretty sure that's wrong so need help with it.
For the second one, I have no idea at all...
Any help would be great! Thanks!

1) So you got
...? I don't know how you obtained this but it's certainly incorrect.
This is basically the summation of the 4th power of all integers up to n. The standard formula for this is:
2) We can find a pattern if we keep expanding this:
The limit log n - 1 is because we keep dividing the parameter to T by 2, so the substitution as above can continue for log n lines until, say T(1) or wherever the stopping condition is. Continuing using the logarithm rules (google them if you don't know):
Both summations have log n terms. Since the 1st summation does not depend on i at all, we simply multiply by log n. The 2nd summation is given by a standard formula for summation of integers from 1 (or 0, doesn't matter in this case):

Related

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.

When to use backtracking?

Sometimes I see a problem and I'm not sure whether my first instinct should be to brute force all possible solutions + memoize or try to solve the problem intelligently. For example, this problem:
Given a positive integer n and you can do operations as follow:
If n is even, replace n with n/2. If n is odd, you can replace n with
either n + 1 or n - 1. What is the minimum number of replacements
needed for n to become 1?
How does one know not to code something that tries every single option for any given n (for example: 1 + [func(n+1), func(n-1), func(n/2)].min instead of looking for a more intelligent solution? How do you know to have that instinct?

Time complexity Big Oh using Summations

Few questions about deriving expressions to find the runtime using summations.
The Big-Oh time complexity is already given, so using summations to find the complexity is what I am focused on.
So I know that there are 2 instructions that must be run before the first iteration of the loop, and 2 instructions that have to be run, (the comparison, and increment of i) after the first iteration. Of course, there is only 1 instruction within the for loop. So deriving I have 2n + 3, ridding of the 3 and the 2, I know the time complexity is O(n).
Here I know how to start writing the summation, but the increment in the for loop is still a little confusing for me.
Here is what I have:
So I know my summation time complexity derivation is wrong.
Any ideas as to where I'm going wrong?
Thank you
Just use n / 2 on the top and i = 1 on the bottom:
The reason it's i = 1 and not i = 0 is because the for loop's condition is i < n so you need to account for being one off since in the summation, i will increase all the way up to n / 2 and not 1 short.

Count permutations of N A's and B's

Given N "A"s and N "B"s. We need to arrange them such that if A is on left of B then our solution increase by +1 and also we need to maintain that at every point the number of A's must be greater than or equal to number of B's.
Now we need to count such permutations of these 2*N alphabets such that solution is equal to K every time.
Example : Say N=4 and K=2 then here answer is 6.
6 possible ways are :
ABAAABBB
AABBAABB
AABAABBB
AAABABBB
AAABBABB
AAABBBAB
My approach : I am having O(N*K) approach to solve this problem by doing brute type solution.
Make a function say F(last,Acount,K) and then check if we can place A or B their satisfying the conditions.But problem is N and K can be large .
So how to solve this problem
Short answer: Narayana numbers is what you need.
I've spent whole saturday researching your problem. Thanks for an interesting question :) Here I would like to tell you my steps to solve it if you are interested.
You said that you can brute force the problem for a small inputs. For an algorithmic problems this ofthen might give you such an insight for better solution (e.g. if you find out some relations and guess the generating function). So I did brute force too (with dynamic programming aproach) and looked at given numbers. First time I wrote it to my output file wrong way (for every K for all N one after another in one column) so I didn't find some beatiful relations. That's why I didn't find answer that time and spent some more to get better reccurent function.
Then I tried to deduce it to nonreccurent function but failed (I think because it wasn't the best one possible). However doing this I found relations like Pascal triangle has (kind of symmetry) and then wrote numbers sequence to the output file in a triangle way.
It looked like very nice sequence so I just googled some of its numbers and found links to Narayana numbers.
Then I tried to deduce nonreccurent formula with no success again (now I could check its correctness because the sequence formula is already knonwn) :) So this time I don't know exactly how Narayana numbers' formula is given although the formula seems simple and small but you can search more if you are interested. I wish I go deep more but I'm afraid of spending the whole holidays for it :)
Here my brute force solution #1 and better reccurent solution #2. And here the outputs I've got in a triangle way (word wrap makes it ugly so be careful).
Also, thanks DavidEisenstat for pointing the right way in comment to your question. I checked that link but didn't go further googling to find a solution. Although that would be the shortest path to the answer your question.
UPDATE I didn't provide implementation of fast calculation of combinations. There're different ways to do this which you can simply find in the internet including its implementations. The complexity of calculations would be O(N) so you will pass the execution time bounds you have. Or if you need to answer the query (with different N and K) multiple times, you can precalculate factorial for every number from 1 to N modulo (1e6 + 9) and then use them to calculate combinations with O(1).
Now that there's a spoiler, let me expand on my comment.
Given a string with n ('s and n )'s, append a ). Exactly one of its n + 1 rotations ending in ) begins with a length-2n parenthesized expression. This is one way to prove the Catalan formula
C(n) = (2n choose n) / (n + 1).
For this problem, we want to count only the parenthesized expressions that have k occurrences of (). The number of ordered partitions of n elements into k nonempty parts is (n - 1) choose (k - 1), by choosing k - 1 positions out of n - 1 to insert part boundaries. By partitioning n + 1 into k nonempty parts also, we can count the number of length-(2n + 1) strings that begin with (, end with ), and have n ('s and n + 1 )'s and k ()'s as
((n - 1) choose (k - 1)) (n choose (k - 1)).
Of these strings, exactly k rotations result in strings of the same form, hence the division by k to get the number that are parenthesized properly. (There is no rotational symmetry because if k > 1 then k fails to divide n or n + 1.) The final answer is
((n - 1) choose (k - 1)) (n choose (k - 1)) / k.
To compute the binomial coefficients quickly, cache the factorials and their inverses modulo the modulus up to the maximum value of n.

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

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.

Resources