Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn’t matter.

For example, for N = 4 and S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}. So output should be 4. For N = 10 and S = {2, 5, 3, 6}, there are five solutions: {2,2,2,2,2}, {2,2,3,3}, {2,2,6}, {2,3,5} and {5,5}. So the output should be 5.

  • Optimal Substructure
    To count total number solutions, we can divide all set solutions in two sets.

    • Solutions that do not contain mth coin (or Sm).
    • Solutions that contain at least one Sm.

Let count(S[], m, n) be the function to count the number of solutions, then it can be written as sum of count(S[], m-1, n) and count(S[], m, n-Sm).

Therefore, the problem has optimal substructure property as the problem can be solved using solutions to subproblems.

  • Overlapping Subproblems

Following is a simple recursive implementation of the Coin Change problem. The implementation simply follows the recursive structure mentioned above.

[pastacode lang=”c” manual=”%23include%3Cstdio.h%3E%0A%20%0A%2F%2F%20Returns%20the%20count%20of%20ways%20we%20can%20sum%20%20S%5B0…m-1%5D%20coins%20to%20get%20sum%20n%0Aint%20count(%20int%20S%5B%5D%2C%20int%20m%2C%20int%20n%20)%0A%7B%0A%20%20%20%20%2F%2F%20If%20n%20is%200%20then%20there%20is%201%20solution%20(do%20not%20include%20any%20coin)%0A%20%20%20%20if%20(n%20%3D%3D%200)%0A%20%20%20%20%20%20%20%20return%201%3B%0A%20%20%20%20%20%0A%20%20%20%20%2F%2F%20If%20n%20is%20less%20than%200%20then%20no%20solution%20exists%0A%20%20%20%20if%20(n%20%3C%200)%0A%20%20%20%20%20%20%20%20return%200%3B%0A%20%0A%20%20%20%20%2F%2F%20If%20there%20are%20no%20coins%20and%20n%20is%20greater%20than%200%2C%20then%20no%20solution%20exist%0A%20%20%20%20if%20(m%20%3C%3D0%20%26%26%20n%20%3E%3D%201)%0A%20%20%20%20%20%20%20%20return%200%3B%0A%20%0A%20%20%20%20%2F%2F%20count%20is%20sum%20of%20solutions%20(i)%20including%20S%5Bm-1%5D%20(ii)%20excluding%20S%5Bm-1%5D%0A%20%20%20%20return%20count(%20S%2C%20m%20-%201%2C%20n%20)%20%2B%20count(%20S%2C%20m%2C%20n-S%5Bm-1%5D%20)%3B%0A%7D%0A%20%0A%2F%2F%20Driver%20program%20to%20test%20above%20function%0Aint%20main()%0A%7B%0A%20%20%20%20int%20i%2C%20j%3B%0A%20%20%20%20int%20arr%5B%5D%20%3D%20%7B1%2C%202%2C%203%7D%3B%0A%20%20%20%20int%20m%20%3D%20sizeof(arr)%2Fsizeof(arr%5B0%5D)%3B%0A%20%20%20%20printf(%22%25d%20%22%2C%20count(arr%2C%20m%2C%204))%3B%0A%20%20%20%20getchar()%3B%0A%20%20%20%20return%200%3B%0A%7D” message=”C” highlight=”” provider=”manual”/]

It should be noted that the above function computes the same subproblems again and again. See the following recursion tree for S = {1, 2, 3} and n = 5.

[ad type=”banner”] The function C({1}, 3) is called two times. If we draw the complete tree, then we can see that there are many subproblems being called more than once.

C() --> count()
                              C({1,2,3}, 5)                     
                           /                \
                         /                   \              
             C({1,2,3}, 2)                 C({1,2}, 5)
            /     \                        /         \
           /        \                     /           \
C({1,2,3}, -1)  C({1,2}, 2)        C({1,2}, 3)    C({1}, 5)
               /     \            /    \            /     \
             /        \          /      \          /       \
    C({1,2},0)  C({1},2)   C({1,2},1) C({1},3)    C({1}, 4)  C({}, 5)
                   / \      / \       / \        /     \    
                  /   \    /   \     /   \      /       \ 
                .      .  .     .   .     .   C({1}, 3) C({}, 4)
                                               /  \
                                              /    \  
                                             .      .

Since same suproblems are called again, this problem has Overlapping Subprolems property. So the Coin Change problem has both properties of a dynamic programming problem. Like other typical Dynamic Programming(DP) problems, recomputations of same subproblems can be avoided by constructing a temporary array table[][] in bottom up manner.

Dynamic Programming Solution

[pastacode lang=”java” manual=”%2F*%20Dynamic%20Programming%20Java%20implementation%20of%20Coin%0A%20%20%20Change%20problem%20*%2F%0Aimport%20java.util.Arrays%3B%0A%20%0Aclass%20CoinChange%0A%7B%0A%20%20%20%20static%20long%20countWays(int%20S%5B%5D%2C%20int%20m%2C%20int%20n)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2FTime%20complexity%20of%20this%20function%3A%20O(mn)%0A%20%20%20%20%20%20%20%20%2F%2FSpace%20Complexity%20of%20this%20function%3A%20O(n)%0A%20%0A%20%20%20%20%20%20%20%20%2F%2F%20table%5Bi%5D%20will%20be%20storing%20the%20number%20of%20solutions%0A%20%20%20%20%20%20%20%20%2F%2F%20for%20value%20i.%20We%20need%20n%2B1%20rows%20as%20the%20table%20is%0A%20%20%20%20%20%20%20%20%2F%2F%20constructed%20in%20bottom%20up%20manner%20using%20the%20base%0A%20%20%20%20%20%20%20%20%2F%2F%20case%20(n%20%3D%200)%0A%20%20%20%20%20%20%20%20long%5B%5D%20table%20%3D%20new%20long%5Bn%2B1%5D%3B%0A%20%0A%20%20%20%20%20%20%20%20%2F%2F%20Initialize%20all%20table%20values%20as%200%0A%20%20%20%20%20%20%20%20Arrays.fill(table%2C%200)%3B%20%20%20%2F%2FO(n)%0A%20%0A%20%20%20%20%20%20%20%20%2F%2F%20Base%20case%20(If%20given%20value%20is%200)%0A%20%20%20%20%20%20%20%20table%5B0%5D%20%3D%201%3B%0A%20%0A%20%20%20%20%20%20%20%20%2F%2F%20Pick%20all%20coins%20one%20by%20one%20and%20update%20the%20table%5B%5D%0A%20%20%20%20%20%20%20%20%2F%2F%20values%20after%20the%20index%20greater%20than%20or%20equal%20to%0A%20%20%20%20%20%20%20%20%2F%2F%20the%20value%20of%20the%20picked%20coin%0A%20%20%20%20%20%20%20%20for%20(int%20i%3D0%3B%20i%3Cm%3B%20i%2B%2B)%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(int%20j%3DS%5Bi%5D%3B%20j%3C%3Dn%3B%20j%2B%2B)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20table%5Bj%5D%20%2B%3D%20table%5Bj-S%5Bi%5D%5D%3B%0A%20%0A%20%20%20%20%20%20%20%20return%20table%5Bn%5D%3B%0A%20%20%20%20%7D%0A%20%0A%20%20%20%20%2F%2F%20Driver%20Function%20to%20test%20above%20function%0A%20%20%20%20public%20static%20void%20main(String%20args%5B%5D)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20int%20arr%5B%5D%20%3D%20%7B1%2C%202%2C%203%7D%3B%0A%20%20%20%20%20%20%20%20int%20m%20%3D%20arr.length%3B%0A%20%20%20%20%20%20%20%20int%20n%20%3D%204%3B%0A%20%20%20%20%20%20%20%20System.out.println(countWays(arr%2C%20m%2C%20n))%3B%0A%20%20%20%20%7D%0A%7D” message=”Java” highlight=”” provider=”manual”/]

Output:

4

Time Complexity: O(mn)

[ad type=”banner”]