algorithmmathbig-orecurrence

How to solve T(n) = 5T(n/2) + O(nlogn) using recursion


So that might be silly, but I'm stuck with this recursion T(n) = 5T(n/2) + O(nlogn). I know from Master Theorem that it's supposed to be O(n), but I can't really get there.

So far I got to a point of O(n)

I just wanted to know if I'm going the right direction with that


Solution

  • You're definitely on the right track here! Let's see if we can simplify that summation.

    First, notice that you can pull out the log n term from the summation, since it's independent of the sum. That gives us

    (n log n) (sum from k = 0 to lg n (5/2)k)

    That sum is the sum of a geometric series, so it solves to

    ((5/2)log n + 1 - 1) / (5/2 - 1)

    = O((5/2)lg n)

    Here, we can use the (lovely) identity that alogb c = clogb a to rewrite

    O((5/2)lg n) = O(nlg 5/2)

    = O(nlg 5 - 1)

    And plugging that back into our original formula gives us

    n log n · O(nlg 5 - 1) = O(nlg 5 log n).

    Hmmm, that didn't quite work. We're really, really close to having something that works here, though! A good question to ask is why this didn't work, and for that, we have to go back to how you got that original summation in the first place.

    Let's try expanding out a few terms of the recurrence T(n) using the recursion method. The first expansion gives us

    T(n) = 5T(n / 2) + n log n.

    The next one is where things get interesting:

    T(n) = 5T(n / 2) + n log n

    = 5(5T(n / 4) + (n / 2) log (n / 2)) + n log n

    = 25T(n / 4) + (5/2) log (n / 2) + n log n

    Then we get

    T(n) = 25T(n / 4) + (5/2) log (n/2) + n log n

    = 25(5T(n / 8) + (n / 4) log (n / 4)) + (5/2) log (n/2) + n log n

    = 125T(n / 8) + (25/4)n log (n / 4) + (5/2) log (n/2) + n log n

    The general pattern here seems to be the following sum:

    T(n) = sum from i = 0 to lg n (5/2)kn lg(n/2k)

    = n sum from i = 0 to lg n (5/2)k lg(n/2k)

    And notice that this is not your original sum! In particular, notice that the log term isn't log n, but rather a function that grows much more slowly than that. In fact, as k gets bigger, that logarithmic term gets much, much smaller. In fact, if you think about it, the only time we're really paying the full lg n cost here is when k = 0.

    Here's a cute little trick we can use to make this sum easier to work with. The log function grows very, very slowly, so slowly, in fact, that we can say that log n = o(nε) for any ε > 0. So what what happens if we try upper-bounding this summation by replacing lg (n / 2k) with (n / 2k)ε for some very small but positive ε? Well, then we'd get

    T(n) = n sum from i = 0 to lg n (5/2)k lg(n/2k)

    = O(n sum from i = 0 to lg n (5/2)k (n / 2k)ε)

    = O(n sum from i = 0 to lg n (5/2)k nε (1 / 2ε)k)

    = O(n1+ε sum from i = 0 to lg n (5 / 21+ε))

    This might have seemed like some sort of sorcery, but this technique - replacing logs with tiny, tiny polynomials - is a nice one to keep in your back pocket. It tends to come up in lots of contexts!

    The expression we have here might look a heck of a lot worse than the one we started with, but it's about to get a lot better. Let's imagine that we pick ε to be sufficiently small - say, so that that 5 / 21+ε is greater than one. Then that inner summation is, once again, the sum of a geometric series, and so we simplify it to

    ((5/21+ε)lg n + 1 - 1) / (5/21+ε - 1)

    = O((5/21+ε)lg n)

    = O(nlg (5/21+ε)) (using our trick from before)

    = O(nlg 5 - 1 - ε)

    And that's great, because our overall runtime is then

    T(n) = O(n1+ε nlg 5 - 1 - ε)

    = O(nlg 5),

    and you've got your upper bound!

    To summarize:

    Hope this helps!