испытайте это:
System.Collections.ObjectModel.Collection<BusinessObject>
это делает ненужным для реализации основного метода как CollectionBase, делают
Самый простой / самый общий способ избавиться от рекурсии, как правило, - использовать вспомогательный стек - вместо рекурсивных вызовов вы помещаете их аргументы в стек и выполняете итерацию. Когда вам нужен результат рекурсивного вызова для продолжения, опять же в общем случае, это немного сложнее, потому что вам также понадобится возможность отправить «запрос продолжения» (который будет исходить из вспомогательного стек, когда результаты известны); однако в этом случае, поскольку все, что вы делаете со всеми результатами рекурсивного вызова, является суммированием, достаточно сохранить аккумулятор, и каждый раз, когда вы получаете числовой результат вместо необходимости выполнять дополнительные вызовы, добавляйте его к аккумулятор.
Однако это, по сути, не фиксированное пространство, поскольку этот стек будет расти. Итак, еще одна полезная идея: поскольку это чистая функция (без побочных эффектов), каждый раз, когда вы обнаруживаете, что вычислили значение функции для определенного набора аргументов, вы можете запоминать соответствие аргумента-результат. Это ограничит количество звонков. Другой концептуальный подход, который приводит почти к таким же вычислениям, - это динамическое программирование [[aka DP]], хотя с DP вы часто работаете снизу вверх, так сказать, «подготавливая результаты для запоминания», а не начинаете с рекурсией и работаем над ее устранением.
Возьмем, к примеру, восходящий DP для этой функции. Вы знаете, что в конечном итоге вы постоянно будете спрашивать «сколько способов внести сдачу на сумму X с помощью самой маленькой монеты» (когда вы сокращаете все до X с помощью различных комбинаций монет из исходного количества
), вы начинаете вычислять эти значения amount
с помощью простой итерации (f (X) = X
/ значение
, если X
точно делится на значение наименьшего достоинства монеты , иначе 0
; здесь значение
равно 1, поэтому f (X) = X для всех X> 0). Теперь вы продолжите, вычисляя новую функцию g (X), способы внести изменения для X с помощью двух наименьших монет: снова простая итерация для увеличения X, с g (x) = f (X) + g (X - значение
) для значения
второй по величине монеты (это будет простая итерация, потому что к тому времени, когда вы вычисляете g (X), вы Мы уже вычислили и сохранили f (X) и все g (Y) для Y значение
) как выше - и с этого момента f (X) вам больше не понадобится, поэтому вы можете повторно использовать это пространство. В общем, для этого потребуется пространство 2 * количество
- еще не «фиксированное пространство», но, подойдя ближе ...
Чтобы совершить последний прыжок в «фиксированное пространство», спросите себя: делайте вам нужно сохранить около всех значений двух массивов на каждом шаге (последнего вычисленного и вычисляемого в данный момент) или только некоторых из этих значений, немного переставить петлю ...?
g (X) = 0 для всех X <= 0). И снова для h (X), способы внести изменения для X с тремя наименьшими монетами - h (X) = g (X) + g (X- значение
) как выше - и с этого момента f (X) вам больше не понадобится, поэтому вы можете повторно использовать это пространство. В общем, для этого потребуется пространство 2 * количество
- еще не «фиксированное пространство», но, подойдя ближе ...
Чтобы совершить последний прыжок в «фиксированное пространство», спросите себя: делайте вам необходимо сохранить около всех значений двух массивов на каждом шаге (последнего вычисленного и вычисляемого в данный момент) или только некоторых из этих значений, немного переставив петлю ...?
g (X) = 0 для всех X <= 0). И снова для h (X), способы внести изменения для X с тремя наименьшими монетами - h (X) = g (X) + g (X- значение
) как выше - и с этого момента f (X) вам больше не понадобится, поэтому вы можете повторно использовать это пространство. В общем, для этого потребуется пространство 2 * количество
- еще не «фиксированное пространство», но, подойдя ближе ...
Чтобы совершить последний прыжок в «фиксированное пространство», спросите себя: делайте вам необходимо сохранить около всех значений двух массивов на каждом шаге (последнего вычисленного и вычисляемого в данный момент) или только некоторых из этих значений, немного переставив петлю ...?
способы внести размен для X с помощью трех наименьших монет - h (X) = g (X) + g (X- значение
), как указано выше - и теперь вы f (X) больше не понадобится, поэтому вы можете повторно использовать это пространство. В общем, для этого потребуется пространство 2 * количество
- еще не «фиксированное пространство», но, подойдя ближе ...
Чтобы совершить последний прыжок в «фиксированное пространство», спросите себя: делайте вам необходимо сохранить около всех значений двух массивов на каждом шаге (последнего вычисленного и вычисляемого в данный момент) или только некоторых из этих значений, немного переставить петлю ...?
способы внести размен для X с помощью трех наименьших монет - h (X) = g (X) + g (X- значение
), как указано выше - и теперь вы f (X) больше не понадобится, поэтому вы можете повторно использовать это пространство. В общем, для этого потребуется пространство 2 * количество
- еще не «фиксированное пространство», но, подойдя ближе ...
Чтобы совершить последний прыжок в «фиксированное пространство», спросите себя: делайте вам нужно сохранить около всех значений двух массивов на каждом шаге (последнего вычисленного и вычисляемого в данный момент) или только некоторых из этих значений, немного переставив петлю ...?
Вы можете решить эту проблему итеративно с помощью динамического программирования за псевдополиномиальное время.
Решение, которое я придумал, состоит в том, чтобы вести подсчет каждого типа монет, которые вы используете в "кошельке"
Основной цикл работает следующим образом; 'denom - текущий номинал, 'changed - общая стоимость монет в кошельке, 'given - количество сдачи, которое мне нужно сделать, и 'clear-up-to вынимает из кошелька все монеты меньше заданного номинала.
#lang scheme
(define (sub changed denom)
(cond
((> denom largest-denom)
combinations)
((>= changed given)
(inc-combinations-if (= changed given))
(clear-up-to denom)
(jump-duplicates changed denom)) ;checks that clear-up-to had any effect.
(else
(add-to-purse denom)
(sub
(purse-value)
0
))))
(define (jump-duplicates changed denom)
(define (iter peek denom)
(cond
((> (+ denom 1) largest-denom)
combinations)
((= peek changed)
(begin
(clear-up-to (+ denom 1))
(iter (purse-value) (+ denom 1))))
(else
(sub peek (+ denom 1)))))
(iter (purse-value) denom))
После прочтения ответа Алекса Мартелли я придумал идею кошелька, но только сейчас дошел до того, чтобы заставить его работать
.