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

Динамическое программирование для Pythonistas

Динамическое программирование – это пугающая тема, когда дело доходит до подготовки к собеседованию. Я всегда беспокоюсь … Tagged Python, DynamicProgramming, Decorator, алгоритмы.

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

Во -первых, давайте поймем мотивацию для динамического программирования. Допустим, у вас есть проблема для решения. Вы понимаете, что если вы решите подзадавшуюся (которая является меньшим экземпляром той же проблемы), вы можете использовать решение этой подзадачи, чтобы решить основную проблему. Это суть рекурсивные алгоритмы . Например, вы хотите рассчитать фактор n Анкет Ну, если бы у тебя был фактор n-1 , вы можете просто умножить n С этим значением, и у вас есть решение. 💯alright теперь, давайте сосредоточимся на том, как получить факториал n-1 Анкет Ну, если бы у тебя был фактор N-2 , вы можете просто несколько n-1 с этим значением, и у вас есть решение. 💯💯. Теперь, как мы получим фактор N-2 ? Если бы у тебя было … Хорошо, я остановлюсь. Вы понимаете .. Вот рекурсивное решение для него –

def fact(n):
    if n <= 1:
        return 1
    return fact(n-1) * n

Все идет нормально. Теперь, что такое динамическое программирование? Это просто Оптимизация по поводу рекурсивных решений, которые становятся актуальными, когда у вас есть несколько вызовов рекурсивной функции для одних и тех же входов. Например, давайте посмотрим на проблему Fibonnaci. Формула Фибоначчи – это Fib (n) (n-1) + fib (n-2) . Теперь, FIB (5) (4) + FIB (3) и FIB (6) (5) + FIB (4) . Оба вычисления требуют значения FIB (4) и в наивной рекурсивной реализации они будут рассчитаны дважды. Хм, это не очень эффективно. Посмотрим, сможем ли мы добиться большего. Давайте просто кэшируем решения, чтобы мы не перепроизводили их.

solution_cache = {}

def fib(n):
    # retrieve from cache if present
    if n in solution_cache:
        return solution_cache.get(n)

    if n <= 1:
        return n
    value = fib(n-1) + fib(n-2)

    # save to cache before returning
    solution_cache[n] = value
    return value

Это в основном сущность динамического программирования. Храните результаты подзадачи, чтобы нам не приходилось перекачивать их позже. Ну, теперь мы более эффективны, но мы пожертвовали читаемости кода. В так много всего происходит fib функция Наш более ранний код был намного проще. Давайте поднимаем это на ступеньку, сделав очиститель кода с декоратор в Python.

def cache_solution(func):
    solution_cache = {}

    def cached_func(n):
        # retrieve from cache if present
        if n in solution_cache:
            return solution_cache.get(n)
        func_result = func(n)
        # save to cache before returning
        solution_cache[n] = func_result
        return func_result
    return cached_func


@cache_solution
def fib(n):
    if n <= 1:
        return n

    return fib(n-1) + fib(n-2)

То, что мы сделали здесь, разделяют проблемы с решением основной проблемы, то есть вычисление числа Фибоначчи и кэширование решения подпроектов. Это облегчает разработку динамических программных решений. Во -первых, мы можем сконцентрироваться в первую очередь на придумывании рекурсивного раствора. После этого, если нам нужно оптимизировать его, нам просто нужно написать декоратор! В результате код чище и более распространен. Как?

  • fib Функция следует за принципом единственной ответственности только в решении вычисления числа Фибоначчи. Если нам нужно изменить логику, это намного проще сделать.
  • Мы создали многоразовое решение для кэширования решений подзадач. Может быть, у вас есть другая функция foo чьи решения вам нужно кэш. Просто укрась, и все готово!
  • Теперь, допустим, вы хотите использовать внешний кэш (возможно, Редис). Возможно, вы захотите сделать это, потому что вы хотите центральный кэш для всех ваших приложений, или вы хотите сохранить кэш для диска, или вы хотите использовать политику выселения кэша. Теперь все, что вам нужно сделать, это внести изменения в cache_solution Декоратор, чтобы сохранить решение для Redis (в отличие от словаря в местной памяти), и все готово. Теперь вы можете использовать Redis для кэширования решений для всех функций, которые используют этот декоратор!

Оригинал: “https://dev.to/makalaaneesh/dynamic-programming-for-pythonistas-21pl”