It is good to at least understand how recursion works, because some algorithms are naturally recursive and thus much easier to express using recursion.
Also, recursive algorithms (or implementations) are not inherently slower than iterative ones. In fact, every recursive algorithm can be implemented by an equivalent iterative implementation at the cost of having to keep track some intermediate/temporary values yourself, where the recursive version automatically keeps track of those in the function call stack.
One example of a naturally recursive algorithm is if you want to apply an operation to all the nodes of a tree. The most natural implementation here is to have a function that performs the operation on one node and calls itself recursively for each of the children of the node.
For some algorithms, like calculating a Fibonacci sequence, recursion seems natural, but a naive implementation will be much slower than an iterative implementation, because the recursive version keeps re-doing the same work over and over again. This just means that for those particular algorithms, recursion may not be the best choice, or that you need to use some techniques to remember intermediate values that might be needed again elsewhere in the algorithm.
For other algorithms, in particular those that use divide-and-conquer tactics, you will find that you need a stack to keep track of some thing in the iterative solution. In those cases, a recursive version is much cleaner, because the stack handling becomes implicit.
There are two problems here:
- Make change for a given situation, and,
- Permutate the given situation to find other answers.
These both together makes things rather confusing. So, you'll have to really try to keep these issues separate.
The first thing you should try to realize that result of any given invocation or level of the solution that you're looking for is a set or an array of answers, rather than a single answer, due to the permutation requirements.
If you factored out the permutations part, the resulting answer is a set of a count of coins by denominations, so already with a single best change answer, you have a a result type that is a set of pairs. When you then factor in the permutations, you have an array of those sets.
So, a solution should make perhaps the best possible answer (amount of change) for the situation, and then also permutate the situation so that another answer can appear. I would submit that these would end up as different parts of the the code. For example, when you traverse a tree ("in order"), you start: (1) traverse left, then (2) work self, then (3) traverse right. Each of these steps is clearly visible as distinguished from each other in the code.
Lastly, the permutations need to limit the amount of coins of each type otherwise, I don't think you'll hit all the permutations. So, the input needs to describe denominations and both either infinite quantity or limited quantity. Then a permutation can limit quantity first, then only limit denominations (which naturally falls out of quantity becoming limited to zero).
In short, you need to seriously inspect the type or shape of the result you're expecting for such a problem, and, similar to be said for the type or shape of the input you're providing.
(Also, you're working in a language that has limited type assistance, whereas if you were in C# or Java you'd get good help from the language and compiler about proper types.)
Best Answer
You're in luck! There (sort-of) is!
What you often want to do is identify the 2/3 cases:
That is:
Think of an example (DFS over a binary search tree):
So here we have:
So now think of in-order traversal of the same tree:
In the case of in-oder traversal it looks like:
Almost all recursive functions will have these elements. Identifying them and putting them in the right order is key.