Применение памятки к проблеме смены монет - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь решить следующую проблему (из CodeRust 3.0 ):

enter image description here

Я думал, что яиспользовать следующее рекурсивное отношение: в этом примере число способов сделать 7 с номиналами (1, 2, 5) является суммой количества способов сделать 0, 1, ..., 7 с номиналами (2, 5) (то есть один рекурсивный вызов наменьший набор номиналов для каждого выбора номера первой монеты, 1).

Чтобы применить памятку, я решил использовать functools.lru_cache().Вот мое решение до сих пор (включая pytest модульные тесты):

import pytest
import functools


@functools.lru_cache()
def solve_coin_change_dp(denominations, amount):
    if amount == 0:
        return 1
    if amount < 0:
        return 0
    if not denominations:
        return 0

    return sum(
        solve_coin_change_dp(
            denominations[1:],
            amount - i * denominations[0])
        for i in range(amount // denominations[0] + 1))


@pytest.fixture
def denominations():
    return (1, 2, 5)


def test_trivial():
    assert solve_coin_change_dp((1,), 1) == 1


def test_1(denominations):
    assert solve_coin_change_dp(denominations, 1) == 1


def test_2(denominations):
    assert solve_coin_change_dp(denominations, 2) == 2


def test_3(denominations):
    assert solve_coin_change_dp(denominations, 3) == 2


def test_4(denominations):
    assert solve_coin_change_dp(denominations, 4) == 3


def test_5(denominations):
    assert solve_coin_change_dp(denominations, 5) == 4


def test_7(denominations):
    assert solve_coin_change_dp(denominations, 7) == 6


def test_big_amount(denominations):
    solve_coin_change_dp(denominations, 1000)


if __name__ == "__main__":
    pytest.main([__file__, '--duration', '1'])

Проблема в том, что lru_cache, похоже, совсем не помогает ускорить реализацию.Для ввода 1000 программе по-прежнему требуется ~ 10 с для запуска:

coin_changing.py ........                                                [100%]

=========================== slowest 1 test durations ===========================
10.31s call     coin_changing.py::test_big_amount
========================== 8 passed in 10.35 seconds ===========================

Однако, если я рассмотрю вызовы функций, я бы ожидал, что произойдет «сохранение» из-за запоминания.Например, вызов с аргументами (1, 2, 5), 5 приведет к (2, 5), 5, (2, 5), 4, (2, 5), 3, (2, 5), 2, (2, 5), 1 и (2, 5), 0.Первое и третье из них, в свою очередь, должны в какой-то момент привести к (5,), 3, и в этом случае один из них может использовать кэшированный результат.

Короче говоря, почему это приложение мемоизации не работает?

1 Ответ

0 голосов
/ 22 октября 2018

lru_cache - это LRU-кеш .Например, он высвобождает элемент «Наименее недавно использованный», когда кэш заполнен и требуется вставить новый элемент.Размер кэша по умолчанию - 128. Запомненные результаты вытесняются.

Установите maxsize=None для использования неограниченного кэша без LRU:

@lru_cache(maxsize=None)
def ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...