Оба эти подхода верны. Действительно допустимо иметь несколько рекурсивных вызовов из функции, и смысл в том, что вы думаете - просто выполните один вызов, затем следующий, затем следующий и т. Д.
Интересно, я не думаю, что рекурсивная версия совершает экспоненциально много вызовов. Он делает не более двух рекурсивных вызовов, но каждый из них имеет проблему, размер которой (примерно) вдвое меньше исходного вызова. По сути, повторение выглядит так:
T(1) = 1
T(2) = 1
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
Я использую «меньше или равно здесь», чтобы сказать, что в лучшем случае вы могли бы просто сделать один звонок, но в худшем случае вы сделаете максимум два.
Я хочу доказать, что эта функция T (n) <= max {cn + d, a} для некоторых констант c, d и a. Это докажет, что T (n) = O (n) и, таким образом, делает самое большее линейно много вызовов. В качестве нашего базового случая мы имеем, что </p>
T(1) = 1
T(2) = 1
так что давайте установим a = 1. Для индуктивного шага мы рассмотрим три случая. Сначала рассмотрим, когда floor (n / 2) <= 2 и floor (n / 2 + 1) <= 2: </p>
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
<= 1 + 1 + 1
<= 3
Если предположить, что cn + d> = 3, когда n = 3 или n = 4, то это работает правильно. В частности, это означает, что 3c + d> = 3 и 4c + d> = 3.
В следующем случае, давайте посмотрим, что произойдет, если floor (n / 2) <= 2 и floor (n / 2 + 1)> = 2. Тогда мы получим это
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
<= 1 + max{c(n / 2 + 1) + d, 1} + 1
<= 2 + max{c(n / 2 + 1) + d, 1}
<= 3 + c(n / 2 + 1) + d
Итак, если у нас есть 3 + c (n / 2 + 1) + d <= cn + d, это утверждение остается в силе. Обратите внимание, что мы только в этом случае, если n = 5, и это означает, что мы должны иметь это </p>
3 + c(n / 2 + 1) + d <= cn + d
3 + c(n / 2 + 1) <= cn
3 + c(5 / 2 + 1) <= 5c
3 + 5c/2 + c <= 5c
3 + 7c/2 <= 5c
4 <= 3c / 2
8 / 3 <= c
Итак, мы должны иметь это с> = 8/3.
И, наконец, случай, когда ни n / 2, ни n / 2 + 1 не меньше трех:
T(n) <= T(n / 2) + T(n / 2 + 1) + 1
<= c(n / 2) + d + c(n / 2 + 1) + d + 1
<= cn / 2 + cn / 2 + c + 2d + 1
= cn + c + 2d + 1
Это меньше, чем cn + d, если
cn + c + 2d + 1 <= cn + d
c + 2d + 1 <= d
c + d + 1 <= 0
Это работает, если d = -c - 1.
Ранее мы знали, что 3c + d> = 3, что работает, если 2c - 1> = 3 или 2c> = 4, поэтому c> = 2. У нас также есть 4c + d> = 3, что также работает, если c> = 2. Допуская c = 8/3, мы получаем, что d = -11 / 3, поэтому
T(n) <= max{8n/3 - 11/3, 1}
Так что T (n) = O (n) и рекурсия делает только линейно много вызовов.
Короткая версия этого заключается в том, что и рекурсивная, и итерационная версии требуют линейного времени. Не бойтесь экспоненциального разрыва рекурсии, не будучи уверенным, что он экспоненциальный. :-) Хотя по общему признанию, в этом случае мне действительно больше нравится итеративная версия. Это более понятно, более интуитивно понятно и более быстро O (n).