def mystery11(n):
  if n < 1: return n
  def mystery12(n):
    i = 1
    while i < n:
      i *= 2
    return i
  return mystery11(n/2) + mystery11(n/2) + mystery12(n-2)

У меня есть вопрос по поводу кода выше. Я полностью понимаю, что без последнего рекурсивного вызова mystery12 время выполнения кода (mystery11) было бы тета (n). Но я не верю, что на каждом уровне тэта (log (n)) работа ведется.

На первом уровне мы делаем log (n), на следующем уровне мы делаем 2log (n / 2), затем 4log (n / 4) ... но это не похоже на log (n) на каждом уровне (он чувствует себя ближе к 2log (n) на втором уровне и 4log (n) на третьем уровне и т. д.)

Я также пробовал Wolfram Alpha, и я просто получил решений не существует . Но отлично работает без термина log (n).

Итак, является ли это решение правильным тэта (nlog (n))? И если нет, то каково реальное решение?

Ps . Извинения, если что-то в моем посте не этикет, это моя вторая публикация на Stackoverflow. Оставьте комментарий, и я это исправлю.

-1
Thomas 13 Мар 2018 в 11:06

2 ответа

Лучший ответ

Поскольку mystery12 не зависит от каких-либо внешних функций / переменных, давайте сначала рассмотрим его.

После j -й итерации цикла while i = 2^j. Таким образом, максимальное количество циклов определяется уравнением 2^j >= n или j = ceil(log2(n)), где ceil округляется до ближайшего целого числа.


Теперь о mystery11. Каждый вызов содержит 2 рекурсивных вызова mystery11 с аргументом n / 2 и вызов mystery12 с аргументом n - 2. Это дает рекуррентное отношение временной сложности (C - некоторая положительная константа):

enter image description here

Вы уже правильно сделали вывод, что глубина рекурсии равна m ~ log n. Точное значение: m = ceil(log2(n)). Используя тот факт, что число, округленное в большую сторону, отличается от самого себя менее чем на 1, мы можем исключить некоторые скобки для округления:

enter image description here


Давайте сначала рассмотрим B. Возникает проблема - выражение внутри логарифма может быть отрицательным. Это смягчается тем фактом, что цикл while mystery12 never выполняется, если n - 2 < 1 - то есть его сложность может быть сокращена до O(1) в этом пограничном случае. Следовательно, сумма ограничена сверху следующим:

enter image description here

Где мы использовали разложение Тейлора log. Следовательно, B можно игнорировать в нашем анализе, так как он уже затмевается первым членом.


Теперь рассмотрим A. Это немного утомительное суммирование, которое я буду использовать Wolfram Alpha для вычисления:

enter image description here

Следовательно, общая временная сложность mystery11 равна Θ(n) , а не Θ(n log n), как прогнозировалось.


Почему это? Причина в том, что «каждый рекурсивный вызов выполняет log n работу» - n здесь не то же самое, что исходное значение n, переданное в mystery11 ({{X4} } в общей временной сложности). На каждом уровне рекурсии n уменьшается экспоненциально, поэтому:

Мы не можем наивно умножать объем работы, выполненной за один вызов, на количество рекурсивных вызовов.

Это относится к анализу сложности в целом.

0
meowgoesthedog 13 Мар 2018 в 12:07

Извините, я не мог понять, в чем ваш вопрос.

Это кажется мне неясным.

Что бы это ни было,

Я сделал математику в соответствии с твоим «загадочным» кодом.


Допустим, «m1» - это тайна11, «m2» - это тайна12.

Без м2,

Стоимость времени будет такой.

m1(n)
= 2*m1(n/2)
= 2*( m1(n/4) + m1(n/4) ) = 4*m1(n/4)
= .....
= 2^k * m1( n / 2^k )

Для к, который составляет 2 ^ о,

2 ^ k = n.

Тогда временная стоимость для m1 (n) равна n * m1 (1) = n.


Временная стоимость m2, очевидно, равна log (n).

С м2,

Стоимость времени меняется, как это.

m1(n)
= 2*m1(n/2) + log(n)
= 2*( m1(n/4) + m1(n/4) + log(n) ) + log(n) = 4*m1(n/4) + ( log(n) + 2log(n) )
= ....
= 2^k * m1(n/2^k) + ( log(n) + 2log(n) + 4log(n) ... 2^(k-1)*log(n) )
= 2^k * m1(n/2^k) + log(n) * ∑( 2^(k-1) ) ( where k is from 1 to k )
= 2^k * m1(n/2^k) + log(n)/2 * ∑( 2^k )
= 2^k * m1(n/2^k) + log(n)/2 * ( 2^(k+1) - 1 )
= 2^k * m1(n/2^k) + 2^k * log(n) - log(n)/2

Как и предыдущий,

Для к, который составляет 2 ^ о н,

2^k * m1(n/2^k) + 2^k * log(n) - log(n)/2
= n * m1(1) + n*log(n) - log(n)/2 = n + n*log(n) - log(n)/2

Я верю, что вы можете сделать все остальное отсюда.

Ps . Мои извинения, если это не то, что вы просили.

0
Al.T.Os 13 Мар 2018 в 10:12