Рубрики
Без рубрики

Рекурсия демистифицирована

Автор оригинала: FreeCodeCapm Team.

Сачин Малхотра

Сумасшедший, не так ли?

Ну, я надеюсь, что к концу этой статьи вы будете чувствовать себя более уверенно, какую рекурсию есть и в основном, как мы можем придумать рекурсивное решение проблемы.

Что такое рекурсия?

Как вы объясните рекурсию до 4 лет? Это довольно знаменитый вопрос интервью, и в Интернете есть нагрузки ответов. Мы не будем отвечать на этот вопрос, так как это слишком мейнстрим.

Если вы так умны, как я ??, вы бы объяснили рекурсию кому-то на один год моложе вас. Пусть они объясняют рекурсию кому-то на один год моложе их. Продолжайте, пока у вас нет 5-летнего объяснения рекурсии до 4 лет. Сделанный. [Источник: Re ddit].

В условиях программирования рекурсия

Вышеуказанная функция не имеет полезной работы как таковой, но она демонстрирует рекурсию. Рекурсивное отношение выше будет

T(N) = T(N - 1) + O(1)

Это просто означает, что выполнение для вызова на Random_Function (N) не может продолжаться до звонка на Random_function (N-1) завершено и так далее.

По сути, мы задерживаем выполнение текущего состояния функции до тех пор, пока другой звонок на ту же функцию не завершился и вернул его результат.

Компилятор продолжает сохранять состояние вызова функции сейчас, а затем перемещается на следующий вызов функции и так далее. Итак, компилятор сохраняет состояния функций на стек и использует, что для вычислений и возврата.

По сути, если проблема может быть разбита в аналогичные подпруты, которые могут быть решены индивидуально, а чьи решения могут быть объединены вместе, чтобы получить общее решение, то мы говорим, что может существовать рекурсивное решение проблемы.

Вместо того, чтобы цепляться за это, казалось бы, старое определение рекурсии, мы посмотрим на целую кучу приложений рекурсии. Тогда, надеюсь, все будет ясно.

Факториал числа

Давайте посмотрим, как мы можем узнать факториал числа. До этого давайте посмотрим, что представляет факториал числа и как он рассчитывается.

factorial(N) = 1 * 2 * 3 * .... * N - 1 * N

Проще говоря, факториал числа – это просто продукт терминов от 1 до числа n умноженного друг на друга.

Мы можем просто иметь для Корпус от 1 до n и умножить все термины итеративно, и у нас будет факториал данного числа.

Но, если вы посмотрите внимательно, существует неотъемлемая рекурсивная структура для факториата числа.

factorial(N) = N * factorial(N - 1)

Это похоже на разъединение вычисления на другую функцию, работающую на меньшую версию оригинальной проблемы. Давайте посмотрим, как это отношение разворачивается, чтобы проверить, если решение здесь соответствует тому, которое предусмотрено «|» для петля.

Таким образом, из двух фигур выше, что рекурсивная функция, которую мы определили ранее,

factorial(N) = N * factorial(N - 1)

действительно правильно. Посмотрите на фрагмент кода Python Code, используемый для поиска факториала функции, рекурсивно.

Этот пример был довольно простым. Рассмотрим немного больше, но стандартный пример, чтобы продемонстрировать концепцию рекурсии.

Последовательность фибоначчи

Вы должны быть уже знакомы со знаменитой последовательностью Фибоначчи. Для тех из вас, кто не слышал об этой последовательности или не видел пример раньше, давайте посмотрим.

1 1  2   3     5           8                       13 ..... 

Давайте посмотрим на формулу для расчета номера N ^ Th Fibonacci.

F(n) = F(n - 1) + F(n - 2)where F(1) = F(2) = 1

Очевидно, что это определение последовательности Фибоначчи рекурсивно в природе рекурсивна, поскольку число N ^ Th Fibonacci зависит от предыдущих двух чисел Фибоначчи. Это означает разделить проблему на более мелкие подпроблемы и, следовательно, рекурсию. Посмотрите на код для этого:

Каждая рекурсивная проблема должна иметь две необходимые вещи:

  1. Соотношение рецидива, определяющее состояния проблемы и как главная проблема может быть разбита на более мелкие подблемы. Это также включает в себя базовый случай для остановки рекурсии.
  2. Дерево рекурсиона, которое демонстрирует первые несколько немногих, если не все призывы к рассматриваемому функции. Посмотрите на дерево рекурсиона для рекурсивного отношения последовательностей Фибоначчи.

Дерево рекурсиона показывает нам, что результаты, полученные от обработки двух подкоревших корня N, могут быть использованы для вычисления результата для дерева, укорененного в N. Аналогично для других узлов.

Листья этого дерева рекурсии было бы Фибоначчи (1) или Фибоначчи (2) Оба из которых представляют базовые случаи для этой рекурсии.

Теперь, когда у нас очень базовая понимание рекурсии, какое отношение рецидивов есть, а дерево рекурсиона, давайте перейдем на что-то более интересное.

Примеры!

Я настоятельно верю в решающий номер домочетащика примеров для любой данной темы в программировании, чтобы стать хозяином этой темы. Два примера, которые мы рассмотрели (факториал числа и последовательность Фибоначчи), имели четко определенные рецидивные отношения. Давайте посмотрим на несколько примеров, когда отношение рецидива может быть не так очевидно.

Высота дерева

Чтобы сохранить все возможное для этого примера, мы будем рассматривать только двоичное дерево. Таким образом, двоичное дерево – это структура данных деревьев, в которой каждый узел имеет у большинства двух детей. Один узел дерева обозначен как корня дерева, например:

Давайте определим, что мы подразумеваем под высотой бинарного дерева.

Таким образом, для примерной диаграммы, отображаемой выше, учитывая, что узел, помеченный как А Как корня дерева, самый длинный корень к листовому пути – A → C → E → G → I Отказ По сути, высота этого дерева – 5 Если мы посчитаем количество узлов и 4 Если мы просто посчитаем количество ребер на самом длинном пути.

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

Вышеуказанная фигура показывает нам, что мы можем представлять дерево в форме его субтрее. По сути, структура слева от узла A и структура справа от А также является бинарным деревом само по себе, просто меньше и с различными корневыми узлами. Но, тем не менее, они двоичные деревья.

Какую информацию мы можем получить от этих двух поддель, которые помогут нам найти высоту главного дерева, укоренившись на A?

Если бы мы знали высоту левого поддерева, скажите H1 , а высота правого поддерева, скажем, H2 Тогда мы можем просто сказать, что Максимум два + 1 Для узла A даст нам высоту нашего дерева. Разве это не правильно?

Формализация этого рекурсивного отношения,

height(root) = max(height(root.left), height(root.right)) + 1

Итак, это рекурсивное определение высоты бинарный дерево. Основное внимание уделяется двоичным здесь, потому что мы использовали только два детей узла корень представлен root.left и root.right. Но легко продлить это рекурсивное отношение к N-Ary дерево. Давайте посмотрим на это в коде.

Проблема здесь была значительно упрощена, потому что мы позволили рекурсии сделать всю тяжелую подъем для нас. Мы просто использовали оптимальный Ответы на наши подпроблемы, чтобы найти решение нашей оригинальной проблеме.

Давайте посмотрим на другой пример, который можно решить на подобных строках.

Количество узлов в дереве

Здесь снова рассмотрим двоичное дерево для простоты, но алгоритм и подход могут быть распространены на любой вид дерева по существу.

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

Посмотрите на диаграмму ниже.

Диаграмма говорит все это. Мы уже знаем, что дерево можно разбиться на более мелкие поддеревы. Здесь снова мы можем спросить сами,

Ну, если бы мы знали количество узлов в левом поддереве и количестве узлов в правом поддереве, мы можем просто добавить их вверх и добавлять один для корневого узла, и это дало бы нам общее количество узлов.

Формализация этого мы получаем,

number_of_nodes(root) = number_of_nodes(root.left) +        number_of_nodes(right) + 1

Если вы посмотрите на эту рекурсию, и предыдущий, вы обнаружите, что они чрезвычайно похожи. Единственное, что варьируется, это то, что мы делаем с информацией, которую мы получили из наших подгруппу, и как мы объединили их, чтобы получить ответ.

Теперь, когда мы видели пару легких примеров с бинарным деревом, давайте перейдем на что-то менее тривиальное.

Сортировка слиянием

Учитывая массив номеров, как

4 2 8 9 1 5 2

Нам нужно придумать методику сортировки, которая сортирует их либо в порядке возрастания, либо по убыванию. Там есть много известных методов сортировки для этого, как Быстрая сортировка , Куча сортировки , Radix Сортировать и так далее. Но мы специально посмотрим на технику, называемую сортировку слияния.

Возможно, что многие из вас знакомы с Разделить и завоевать парадигму И это может чувствовать себя резервным. Но нести со мной и читаю!

Идея здесь – сломать его в подблемы.

Это то, что статья о праве? ?

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

Это главная идея здесь. Задача сортировки массива может быть разбита на две меньшие подзадачи:

  • сортировка двух разных половив массива
  • Затем используете те сортированные половины, чтобы получить оригинальный отсортированный массив

Теперь красота о рекурсии – это, вам не нужно беспокоиться о том, как мы получим две отсортированные половины и какую логику пойдут на это. Поскольку это рекурсия, тот же метод вызова Merge_sort отсортировал бы две половины для нас. Все, что нам нужно сделать, это сосредоточиться на том, что нам нужно сделать, как только у нас есть сортированные имеющие у нас.

Давайте пройдемся по коду:

На данный момент мы доверяли и полагались на нашего хорошего друга рекурсии и предполагали, что left_sorted_half и right_sorted_half на самом деле будет содержать две отсортированные половины исходного массива.

Так, что дальше?

Вопрос в том, как их объединить их как-то, чтобы дать весь массив.

Проблема теперь просто сводится к объединению двух сортировков в один. Это довольно стандартная проблема и может быть решена тем, что известно как «двумя палец».

Посмотрите на псевдо-код для лучшего понимания.

let L and R be our two sorted halves. let ans be the combined, sorted array
l = 0 // The pointer for the left halfr = 0 // The pointer for the right halfa = 0 // The pointer for the array ans
while l < L.length and r < R.length {      if L[l] < R[r] {           ans[a] = L[l]           l++       } else {           ans[a] = R[r]           r++      }}
copy remaining array portion of L or R, whichever was longer, into ans.

Здесь у нас есть два указателя (пальцы), и мы позиционируем их в начале отдельных половинок. Мы проверяем, какой из них меньше (то есть, какое значение, указанное на пальце меньше), и мы добавляем это значение для нашего сортированного комбинированного массива. Затем мы продвигаем соответствующий указатель (палец) вперед. В конце мы копируем оставшуюся часть более длинного массива и добавить его в заднюю часть АНС множество.

Итак, комбинированный код для слияния – это следующее:

Мы сделаем один последний вопрос, используя рекурсию и доверяю мне, это сложный и довольно запутанный. Но прежде чем двигаться на то, что я буду повторять шаги, которые я следую, когда я должен подумать о рекурсивном решении проблемы.

Шаги, чтобы придумать рекурсивное решение

  1. Попробуйте сломать проблему в подблемы.

2. Как только у вас выяснится подпункты, подумайте о том, какую информацию от вызова к подпроблемам вы можете использовать для решения задачи под рукой. Например, факториал N - 1 найти факториал N , высота левого и правого поддеревья, чтобы найти высоту главного дерева и так далее.

3. Сохраняйте спокойствие и доверять рекурсии! Предположим, что ваши рекурсивные вызовы в подпроблем вернут необходимую информацию, наиболее оптимальную моду.

4. Последний шаг в этом процессе на самом деле использует информацию, которую мы только что получили от подполей, чтобы найти решение основной проблемы. Как только у вас есть, вы готовы комировать ваше рекурсивное решение.

Теперь, когда у нас есть все шаги, выровняемые вверх, давайте перейдем к нашей окончательной проблеме в этой статье. Это называется Сумма расстояний в дереве.

Сумма расстояний в дереве

Давайте посмотрим на то, что вопрос просит нас сделать здесь. Рассмотрим следующее дерево.

В приведенном выше примере сумма путей для узла A (количество узлов на каждый путь от A на все другие вершины в дереве) составляет 9. Отдельные пути упоминаются на диаграмме сама с их соответствующими длинами.

Точно так же рассмотрите сумму расстояний для узла C.

C --> A --> B (Length 2)C --> A (Length 1)C --> D (Length 1)C --> E (Length 1)C --> D --> F (Length 2)Sum of distances (C) = 2 + 1 + 1 + 1 + 2 = 7

Это известно как сумма расстояний, как определено только для одного узла A или C. Нам нужно рассчитать эти расстояния для каждого из узлов в дереве.

Перед тем, как на самом деле решить эту общую проблему, рассмотрим упрощенную версию той же проблемы. Он говорит, что нам просто нужно рассчитать сумму расстояний для данного узла, но мы будем рассматривать дерево, только укоренившись только на данном узле для расчетов.

Итак, для узла C, эта упрощенная версия проблемы спросит нас рассчитать:

C --> D (Length 1)C --> E (Length 1)C --> D --> F (Length 2)Simplified Sum of Distances (C) = 1 + 1 + 2 = 4

Это гораздо более простая проблема для рекурсивно, и окажется полезна в решении исходной проблемы.

Рассмотрим следующее простое дерево.

Узлы B и C являются детьми корня (то есть а).

Мы пытаемся посмотреть, какую информацию мы можем использовать из подполей (детей), чтобы вычислить ответ для корня А Отказ

Примечание Вот мы просто хотим рассчитать сумму путей для данного узла X ко всем его преемникам в собственном поддеревении (дерево, укорененное на узле x).

Нет нисходящих путей из узла B, и поэтому сумма путей 0 для узла B В этом дереве. Давайте посмотрим на узел C . Отказ Так что этот узел имеет 3 разных преемника в F, D и E Отказ Сумма расстояний следующая:

C --> D (Path containing just 1 edge, hence sum of distances = 1)C --> D --> F (Path containing 2 edges, hence sum of distances = 2)C --> E (Path containing just 1 edge, hence sum of distances = 1)

Сумма всех путей у узла C . Для всех его определенных пунктов есть 4, а количество таких дорожек спускается 3.

Обратите внимание на разницу здесь. sum_of_distences Здесь считает количество ребер в каждом пути – с каждым краем, повторяющимся несколько раз, вероятно, из-за их возникновения на разных путях – в отличие от Number_of_Paths , что рассчитывает, ну, количество путей?

Если вы внимательно посмотрите, вы поймете, что количество путей, происходящих вниз, всегда будет количество узлов в дереве, которое мы рассматриваем (кроме корня). Итак, для дерева укоренившись на C, у нас есть 3 пути, один для узла d, один для e, и один для f. Это означает, что количество путей от данного узла к узлам преемника просто общее количество потрясные узлы, так как это дерево. Итак, нет циклов или нескольких ребер.

Теперь рассмотрим узел А. Давайте посмотрим на все новые пути, которые вводятся из-за этого узла А. Забудьте узел B на данный момент и просто сосредоточиться на детском узле C, соответствующем A. Новые наборы пути, которые мы есть:

A --> C (Path containing just 1 edge, hence sum of distances = 1)A --> (C --> D)    (Path containing 2 edges, hence sum of distances = 2)A --> (C --> E)    (Path containing 2 edges, hence sum of distances = 2)A --> (C --> D --> F) (Path containing 3 edges, hence sum of distances = 3)

За исключением первого пути A → C Все остальные такие же, как для узла C, за исключением того, что мы просто изменили все из них и включили один дополнительный узел А Отказ

Если вы посмотрите на диаграмму выше, вы увидите кортеж значений рядом с каждым из узлов A, B и C.

(X, Y) where X is the number of paths originating at that node and going down to the decedents. Y is the sum of distances for the tree rooted at the given node. 

Поскольку узел B не имеет других детей, единственный путь, который он способствует пути A -> ; B к Кортеж (5, 9) выше. Так что давайте поговорим о C.

C имели три пути, идущие к его преемникам. Те три пути (продлены еще одним узлом для A) также становятся тремя путями от к своим преемникам, среди прочего.

N-Paths[A] = (N-Paths[C] + 1) + (N-Paths[B] + 1)

Это точное отношение, которое мы ищем, поскольку касается количества путей узлов преемника на дереве). 1 – это из-за нового пути от корня к ребенку, то есть A -> ; В нашем случае.

N-Paths[A] = 3 + 1 + 0 + 1 = 5

Что касается суммы расстояний, посмотрите на диаграмму и уравнения, которые мы просто написали. Следующая формула становится очень понятной:

Sum-Dist[A] = (N-Paths[C] + 1 + Sum-Dist[C]) + (N-Paths[B] + 1 + Sum-Dist[B])
Sum-Dist[A] = (3 + 1 + 4 + 0 + 1 + 0) = 9

Главное здесь N-пути [C] + Sum-Dist [C] Отказ Мы суммируем их, потому что все пути от C до его потомков в конечном итоге становятся путями от к его потомкам – за исключением того, что они происходят в и проходят через C, и поэтому каждый из длин пути увеличивается на 1. есть . N-пути [C] Пути во всех происходящих от C и их общая длина дается Sum-Dist [C] Отказ

Следовательно, кортеж, соответствующий A = (5, 9). Код Python для алгоритма, который мы обсуждали выше, заключается в следующем:

Любопытный случай посещенного словаря:/

Если вы внимательно посмотрите на код выше, вы увидите это:

# Prevents the recursion from going into a cycle.        self.visited[vertex] = 1

Комментарий говорит, что это посетил Словарь для предотвращения ввода рекурсии цикл.

Если вы обратили внимание до этого, вы знаете, что мы имеем дело с дерево здесь.

Определение структуры данных деревьев не позволяет существовать циклы. Если цикл существует в структуре, то это больше не дерево, он становится графиком. В дереве есть ровно один путь между любыми двумя вершинами. Цикл будет означать, что существует более одного пути между парой вершин. Посмотрите на цифры ниже.

Структура слева – это дерево. У него нет циклов в этом. Существует уникальный путь между любыми двумя вершинами.

Структура справа – это график, существует цикл на графике и, следовательно, есть несколько путей между любой парой вершин. Для этого графика так происходит, что любая пара вершин имеет более одного пути. Это не нужно для каждого графа.

Почти всегда нам дам корень узел дерева. Мы можем использовать корневой узел для прохождения всего дерева без необходимости беспокоиться о каких-либо циклах как таковых Отказ

Однако, если вы прочитали заявление о проблеме ясно, он ничего не говорит о корне дерева.

Это означает, что для дерева нет назначенного корня для дерева. Это может означать, что данное дерево может быть визуализировано и обработано так много разных способов в зависимости от того, что мы считаем корнем. Посмотрите на несколько структур для того же дерева, но с различными корневыми узлами.

Так много разных интерпретаций и родительских дочерних отношений возможны для данного Неоперационное дерево Отказ

Итак, мы начинаем с узла 0 и выполнить обход DF данной структуры. В процессе мы исправим родительские дочерние отношения. Учитывая края в задаче, мы построим нерешенную структуру, подобную графику, которая превращаем в структуру дерева. Взгляд на код должен прояснить некоторые из ваших сомнений:

Каждый узел будет иметь один родитель. У корень не будет ни родителей, а то, как эта логика, узел 0 станет корнем нашего дерева. Обратите внимание, что мы не делаем этот процесс отдельно, а затем вычисляем сумма расстояний вниз Отказ Учитывая дерево, мы пытались найти, для каждого узла, упрощенная сумма расстояний для дерева укоренившись на этом узле.

Таким образом, преобразование от графа на дерево происходит в одной единственной итерации вместе с выявлением суммы расстояний вниз для каждого и каждого узла.

Я снова опубликовал код, чтобы посетил Словарь сейчас гораздо больше смысла. Итак, одна единая рекурсия делает все это для нас. Хороший!

Принося все это вместе

Теперь, когда у нас определена наша структура дерева, а также значения Сумма расстояний сходит вниз Определен для нас, мы можем использовать всю эту информацию для решения оригинальной проблемы Сумма расстояний в дереве.

Как мы это делаем? Лучше всего объяснить этот алгоритм с помощью примера. Таким образом, мы рассмотрим дерево ниже, и мы будем высыхать алгоритм для одного узла. Давайте посмотрим на дерево, которое мы будем рассматривать.

Узел, для которого мы хотим найти сумму расстояний, является 4 Отказ Теперь, если вы помните более простую проблему, мы пытались решить ранее, вы знаете, что у нас уже есть два значения, связанные с каждым из узлов:

  1. Distance_down Какая сумма расстояний для этого узла только с учетом дерева под Отказ
  2. number_of_paths_down Какое количество путей/узлов в дереве укоренившись на рассматриваемом узле.

Давайте посмотрим на аннотированную версию вышеуказанного дерева. Дерево аннотируется кортежами (Distance_down, numbers_of_paths_down) Отказ

Давайте назовем значение, которое мы хотим вычислить для каждого узла как СОД Что означает сумму расстояний, которая является тем, что вопрос первоначально просит нас вычислить.

Предположим, что мы уже вычислили ответ на родительский узел 4 на диаграмме выше. Итак, теперь у нас есть следующая информация для узема, помеченного 2 (родительский узел) доступен:

(sod, distance_down, numbers_of_paths_down) = (13, 4, 3)

Давайте повернем данное дерево и визуализируйте его таким образом, где 2 является корнем дерева по существу.

Теперь мы хотим удалить вклад дерева, укоренившись на 4 от SOD (2) Отказ Давайте рассмотрим все пути от родительского узла 2 для всех других узлов, кроме те, которые в дереве укоренились в 4 Отказ

2 --> 5 (1 edge)2 --> 1 (1 edge)2 --> 1 -->7 (2 edges)2 --> 1 --> 7 --> 9 (3 edges)2 --> 1 --> 7 --> 10 (3 edges)
Number of nodes considered = 6Sum of paths remaining i.e. sod(2) rem = 1 + 1 + 2 + 3 + 3 = 10

Давайте посмотрим, как мы можем использовать значения, которые мы уже рассчитаны, чтобы получить эти обновленные значения.

* N = 8 (Total number of nodes in the tree. This will remain the same for every node. )* sod(2) = 13
* distances_down[4] = 1* number_of_paths_down[4] = 1
* (distances_down[4] does not include the node 4 itself)N - 1 - distances_down[4] = 8 - 1 - 1 = 6
* sod(2) - 1 - distances_down[4] - number_of_paths_down[4] = 13 - 1 - 1 - 1 = 10

Если вы помните это из функции, которую мы определены ранее, вы заметите, что вклад A ребенок Узел к двум значениям Distance_down и numbers_of_paths_down это n_paths + 1 и n_paths + s_paths + 1 соответственно. Естественно, это то, что вы вычитаете, чтобы получить оставшийся дерево.

SOD (4) Представляет сумму ребер на всех путях, происходящих на узле 4 на дереве выше. Давайте посмотрим, как мы можем найти это, используя информацию, которую мы рассчитали до сих пор.

Distance_down [4] Представляет ответ для дерева, укоренившись на узле 4 Но это только считает пути к его преемникам, это все узлы в дереве, укорененные на 4 Отказ Для нашего примера преемник 4 это узел 6 Отказ Итак, это напрямую добавит к окончательному ответу. Давайте назовем это значение Soe_answer Отказ Теперь давайте учитывать все остальные пути.

4 --> 2 (1 edge)4 --> 2 --> 5 (1 + 1 edge)4 --> 2 --> 1 (1 + 1 edge)4 --> 2 --> 1 -->7 (1 + 2 edges)4 --> 2 --> 1 --> 7 --> 9 (1 + 3 edges)4 --> 2 --> 1 --> 7 --> 10 (1 + 3 edges)own_answer = 1
sod(4) = 1 + 1 + 2 + 2 + 3 + 4 + 4 = 17
sod(4) = own_answer + (N - 1 - distances_down[4]) + (sod(2) - 1 - distances_down[4] - number_of_paths_down[4]) = 1 + 6 + 10 = 17

Прежде чем идти Bonkers и начнем делать это, давайте посмотрим на код и объедините все вещи, которые мы обсуждали в примере выше.

Рекурсивное отношение для этой части выглядит следующим образом:

Я просто видел «воспоминание» в коде?

Да, действительно, ты сделал!

Рассмотрим следующее примеру дерева:

Вопрос просит нас найти сумму расстояний для всех узлов в данном дереве. Итак, мы сделаем что-то вроде этого:

for i in range(N):    ans.append(find_distances(N))

Но если вы посмотрите на дерево выше, рекурсивный звонок для узла 5 в конечном итоге расчет ответов на все узлы в дереве. Итак, нам не нужно пересчитать ответы для других узлов снова и снова.

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

По сути, рекурсия основана на родительском узле, а несколько узлов могут иметь тот же родитель. Таким образом, ответ для родителя должен быть рассчитан только один раз, а затем снова использовать снова и снова.

Если вам удалось прочитать статью этой далеко (не обязательно за один растяжение?), Ты потрясающий?

Если вы нашли эту статью полезную, поделитесь как можно больше и распространяйте? Ваше здоровье!