0

I am new to recursion and backtracking. I know I need to be completely comfortable with these concepts before I move on to dynamic programming. I have written a program below that helps me find all the possible combinations for a given amount n and an unlimited number of coins. However, I wish to have my program give me distinct solutions. I am having a hard time figuring out how to do this.

I have found a resource here: Coin Change that uses a top down approach recursively and then modifies it to give distinct combinations using the following formula: count (s, n, total) = count (s, n, total-s[n]) + count(s, n-1, total)

This says that I recurse using the value and then recurse excluding the value and decreasing the coins by 1.

I can't seem to grasp how this works. Also I can for sure say, it would have been quite hard to even think of such a technique on the spot at an interview per say. It seems like some one at some point would have had to spend a considerable amount of time on such a problem to devise such a technique.

Anyhow any help on how I can convert my program to print distinct solutions and how it works will be really appreciated.

public class Recursive {

    static int[] combo = new int[100];
    public static void main(String argv[]) {
        int n = 8;
        int[] amounts = {1, 5, 10};
        ways(n, amounts, combo, 0, 0, 0);
    }

    public static void  ways(int n, int[] amounts, int[] combo, int count, int sum, int index) {
        if(sum == n) {
            printArray(combo, index);
        }

        if(sum > n) {
            return;
        }


        for(int i=0;i<amounts.length;i++) {
            sum = sum + amounts[i];
            combo[index] = amounts[i];
            ways(n, amounts, combo, 0, sum, index + 1);
            sum = sum - amounts[i];
        }
    }

    public static void printArray(int[] combo, int index) {
        for(int i=0;i < index; i++) {
            System.out.print(combo[i] + " ");
        }
        System.out.println();
    }
}

The actual amount of non distinct valid combinations for amounts {1, 2, 5} and N = 10 is 128, using a pure recursive exhaustive technique (Code below).

My question is can an exhaustive search be improved with memoization/dynamic programming. If so, how can I modify the algorithm below to incorporate such techniques.

Spindoctor
  • 434
  • 3
  • 17
  • Possible duplicate of [coin change - all solutions recursive - Java](https://stackoverflow.com/questions/44043531/coin-change-all-solutions-recursive-java) – Prune Feb 26 '19 at 17:33
  • the question is how to go from all sets to distinct sets. What you have provided is a link to is someone not understanding how array references work in java – Spindoctor Feb 26 '19 at 17:36
  • 1
    The combined solution -- that question's modifications on top of the help page referenced -- provide both all of the solutions (instead of just the count) and a walk-through of the recursion logic. – Prune Feb 26 '19 at 17:50
  • ahh..I see there is another link to geeksforgeeks at the top. I now agree with the downvote as my search wasn't thorough enough to find the aforementioned. – Spindoctor Feb 26 '19 at 17:57
  • Right -- the problem is covered quite thoroughly on Stack Overflow and elsewhere on line. You should now have a better set of keywords to help your search. – Prune Feb 26 '19 at 18:04

2 Answers2

2

Simple modification allow to avoid repeats.

Use sorted amounts array.
Starting value of the loop should exclude previous values from amounts.
I used count argument (seems unused)

 for(int i=count;i<amounts.length;i++) {
            sum = sum + amounts[i];
            combo[index] = amounts[i];
            ways(n, amounts, combo, i, sum, index + 1);
            sum = sum - amounts[i];
        }
MBo
  • 77,366
  • 5
  • 53
  • 86
  • Can you please explain why the need to sort? If I wanted to exclude a value, I would just start from index 1 in amounts rather than always starting from 0. – Spindoctor Feb 26 '19 at 18:06
  • 1
    Such approach (no backward steps) always generates ordered (non-decreasing) result sequence, so automatically makes only one set (lexicographicaly smallest) - for example `1 1 3` instead of `1 1 3, 1 3 1, 3 1 1` – MBo Feb 26 '19 at 18:10
  • Superb. Thank you for that. That is a very keen observation. – Spindoctor Feb 26 '19 at 18:12
  • Can I get some help on how to incorporate memoization using the above algorithm? I have seen many solutions that incorporate memoization for a top down approach. But some explanation on how to think about memoization would be greatly appreciated – Spindoctor Feb 27 '19 at 17:22
  • 1
    You can get specific `sum` value by different ways, but the rest of sum is recalculated many times again and again. You can save variants (calculated once) in some table (here complex key might contain sum value and index of starting element). When you enter into this table cell next time - just get ready-to-use variants. – MBo Feb 27 '19 at 17:32
  • thanks, I saved the variants as suggest. I pasted the code below. Any comments are welcome. I used key value pair Sum, Count and re-used count if sum was found in the map. – Spindoctor Mar 04 '19 at 18:48
0
static HashMap<Integer, Integer> memo = new HashMap<Integer, Integer>();

    public static void main(String argv[]) {
        int n = 1000;
        System.out.println(getSteps(n, 0,0 ));
    }

    public static int getSteps(int n, int sum, int count) {

        if(n == sum) {
            return 1;
        }
        if(sum > n) {
            return 0;
        }
        if(memo.containsKey(sum)) {
            return memo.get(sum);
        }
        for(int i=1; i<=3;i++) {
            sum = sum + i;
            count += getSteps(n, sum, 0);
            sum = sum - i;
            memo.put(sum, count);
        }
        return count;
    }
Spindoctor
  • 434
  • 3
  • 17