Заметки из этого туториала

Этот пост содержит заметки, которые я сделал из это видео freeCodeCamp на YouTube. Я включил все определения (теоретическая часть) и проблемы, решаемые в JavasScript.

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

Плюсы:

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

Минусы:

  1. Медлительность из-за перегрузки процессора.
  2. Может привести к ошибкам нехватки памяти/исключениям StackOverflow.
  3. Может быть излишне сложным, если плохо построен.

Стек вызовов:

Стек вызовов — это механизм, с помощью которого интерпретатор (например, интерпретатор JavaScript в веб-браузере) отслеживает свое место в сценарии, вызывающем несколько функций — какая функция выполняется в данный момент и какие функции вызываются из этой функции. и т. д. (подробнее здесь…)

Ошибка в стеке вызовов (StackOverflow): это исключение, которое возникает, когда мы превышаем предварительно выделенный буфер памяти, который есть у нашей программы.

Проблемы:

  1. Перевернуть строку:
  • Базовый вариант: если строка пуста, возврат.
  • Рекурсивная функция. В противном случае вызовите функцию еще раз для подстроки, начинающейся с индекса 1, и добавьте в конец символ с индексом 0.

2. Палиндром:

  • Базовый случай: если длина входной строки равна 0 или 1, возвращается значение true.
  • Рекурсивная функция:проверить, равны ли символы в 0-м индексе и последнем индексе (str.length - 1). Снова верните функцию для подстроки от 1-го индекса до предпоследнего индекса строки.
  • Вернуть false (еще один базовый случай)

3. Десятичное в двоичное:

  • Создайте переменную (результат) для хранения двоичного числа.
  • Базовый случай: если десятичное число равно 0, то возвращается результат.
  • Операция: добавить (десятичный % 2) к предыдущему значению результата. (результат += десятичный % 2)
  • Рекурсивный вызов. Повторно вызовите функцию с частным значением, т. е. decimal/2.

Примечание. Еще один способ рекурсивного преобразования десятичного числа в двоичное.

4. Сумма натуральных чисел:

  • Базовый случай: если число равно нулю, вернуть результат.
  • Операция и рекурсивный вызов: добавьте текущий номер к рекурсивному вызову функции с помощью num – 1.

5. Двоичный поиск:

  • Базовый случай: если левый индекс (меньший) больше правого индекса (больше), возвращается -1.
  • Операция: найдите средний индекс и проверьте, равен ли элемент в среднем индексе целевому, затем верните true.
  • Рекурсивный вызов:
  1. Если элемент больше среднего элемента, вызовите функцию с правым индексом, равным середине-1.
  2. В противном случае вызовите функцию с левым индексом mid+1.

6. Ряд Фибоначчи:

  • Базовый случай: если число равно 0 или 1, вернуть число.
  • Операция + рекурсивный вызов: вернуть сумму вызова функции с (число-1) и (число-2)

Примечание. Это не оптимизированный способ вычисления n-го числа Фибоначчи.

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

  • Базовый вариант: вернуть массив, если length(array) ≤ 1.
  • Операция: вычислить индекс среднего элемента, т. е. length(array)/2.
  • Рекурсивный вызов.Повторный вызов функции от 0-го до середины индекса(левая часть) и от середины индекса до индекса последнего элемента(правая часть).
  • Возвратите вспомогательнуюфункцию, которая объединит левую и правую части.

8. Разворот связанного списка:

  • Базовый вариант: если head и head.next равны нулю, вернуть head.
  • Рекурсивный вызов. Рекурсивно вызовите функцию head.next и сохраните ее в переменной (p).
  • Операция:
  1. Задайте для head.next.next значение head.
  2. Задайте для head.next значение null.
  3. Вернуть переменную (p)

9. Объединить два отсортированных связанных списка:даны две головы h1 и h2 в аргументах

  • Базовый случай: если h1 и h2 равны нулю, вернуть undefined или, если один из них равен нулю, вернуть другой.
  • Рекурсивный вызов + операция:
  1. Если (h1.value ‹ h2.value) рекурсивно вызвать функцию и установить h1.next как function(h1.next, h2) и вернуть h1.
  2. В противном случае рекурсивно вызовите функцию и установите h2.next как function(h1, h2.next) и верните h2.

10. Вставьте значение в двоичное дерево поиска:

  • Базовый случай: если корень bst равен нулю, установите корень в качестве нового значения.
  • Рекурсивный вызов + операция:
  1. Если (value › root.value), то рекурсивно вызовите функцию на root.right
  2. В противном случае вызовите функцию на root.left.

11. Распечатайте все конечные узлы:

  • Базовый случай: если левый и правый дочерние элементы корня равны нулю, то это конечный узел.
  • Рекурсивный вызов:
  1. Если root.left не равно нулю, вызовите function(root.left)
  2. Если root.right не равно нулю, вызовите function(root.right)

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

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

Все исходники: