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

Рекурсия — это мощная концепция программирования, которая позволяет разработчикам писать элегантный и эффективный код. В этом сообщении блога мы рассмотрим рекурсию от основ до продвинутых методов с 10 примерами, иллюстрирующими ключевые концепции.

  1. Основная рекурсия. Первый пример рекурсии — классическая функция факториала. Факториал числа n — это произведение всех положительных целых чисел, меньших или равных n.
function factorial(n) {
  if (n === 0) {
    return 1;
  } else {
    return n * factorial(n-1);
  }
}

A. Базовый вариант. Важно иметь базовый вариант в рекурсии, так как он предотвращает бесконечное выполнение функции. В приведенном выше примере базовый случай — это когда n == 0, а функция возвращает 1.

B. Рекурсивный случай. Рекурсивный случай — это когда функция вызывает сама себя с другим вводом. В факториальном примере рекурсивный случай — это когда функция вызывает себя с входом n-1.

C. Хвостовая рекурсия.Хвостовая рекурсия — это частный случай рекурсии, когда рекурсивный вызов — это последнее, что происходит в функции.

function tailFactorial(n, accumulator=1) {
    if (n === 0) {
        return accumulator;
    } else {
        return tailFactorial(n-1, n*accumulator);
    }
}

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

function fibonacci(n, memo = {}) {
    if (n === 0) {
        return 0;
    } else if (n === 1) {
        return 1;
    } else if (n in memo) {
        return memo[n];
    } else {
        memo[n] = fibonacci(n-1) + fibonacci(n-2);
        return memo[n];
    }
}

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

function binarySearch(arr, x, low=0, high=-1) {
    if (high === -1) {
      high = arr.length - 1;
    }
    if (low > high) {
      return false;
    } else {
      var mid = Math.floor((low + high) / 2);
      if (arr[mid] === x) {
        return true;
      } else if (arr[mid] > x) {
        return binarySearch(arr, x, low, mid-1);
      } else {
        return binarySearch(arr, x, mid+1, high);
      }
    }
}

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

function generatePermutations(arr, index = 0) {
    if (index === arr.length) {
        console.log(arr);
    } else {
        for (let i = index; i < arr.length; i++) {
            [arr[index], arr[i]] = [arr[i], arr[index]];
            generatePermutations(arr, index + 1);
            [arr[index], arr[i]] = [arr[i], arr[index]];
        }
    }
}

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

dfunction longestCommonSubsequence(str1, str2) {
    if (!str1 || !str2) {
        return "";
    } else if (str1[str1.length-1] === str2[str2.length-1]) {
        return longestCommonSubsequence(str1.slice(0, -1), str2.slice(0, -1)) + str1[str1.length-1];
    } else {
        var option1 = longestCommonSubsequence(str1, str2.slice(0, -1));
        var option2 = longestCommonSubsequence(str1.slice(0, -1), str2);
        return option1.length > option2.length ? option1 : option2;
    }
}

6. Рекурсивные структуры данных. Рекурсивные структуры данных — это структуры данных, определяемые рекурсивно, например связанные списки и деревья.

class Node {
  constructor(data, next = null) {
    this.data = data;
    this.next = next;
  }
}

class LinkedList {
  constructor(head = null) {
    this.head = head;
  }
}

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