假如如今有四種硬幣類型:1角,2角,5角和1元。java
你如今是超市收銀員,老闆要求你每次都使用最少的硬幣給用戶找零。git
例如,用戶須要找零6角,你須要找給他 一個5角 + 一個1角,這樣只用到2個硬幣,而不是找給他 六個1角 或者 三個2角。github
面對這樣的問題咱們該如何思考呢?編程
假如當前已經選擇了 i-1 枚硬幣,當選擇下一枚硬幣 i 的時候,面對下面兩種狀況:數組
面對這兩種選擇咱們須要作的就是選擇其中的最優解。spa
下面以找零6角爲例進行一下推算。code
找零1角,可供選擇的硬幣爲1角,那此時的最優解在選擇這1角硬幣和不選擇這1角硬幣中。blog
狀況一:若是選擇這1角硬幣,這意味着須要的硬幣數量 = ((找零1角 - 當前硬幣金額 )所須要的硬幣數量 )+ 1ip
找零1角 - 當前硬幣金額 = 1 -1 = 0,而找零0角須要的硬幣數量爲0,因此第一種狀況須要的硬幣數量 = 0 + 1 = 1get
狀況二:若是不選擇這枚硬幣,這意味着須要的硬幣數量 = 以前 1 - 1 = 0 種硬幣找零1角的最有解。
咱們知道若是硬幣種類爲0,咱們是沒法進行找零的,也就是須要找零的硬幣爲無窮大。
顯然狀況一須要的硬幣數量更少。此時的最優解爲1。
同理咱們能夠推論出後面的結果。下圖顯示了這個推算過程。
如上推算所示,咱們在推演時須要考慮一些邊界條件:
一、若是當前沒有硬幣,是沒法找零的,也就是不管多少硬幣都沒法找零。
二、若是須要找零的金額爲0,那這時候也須要找零。
三、若是須要找零的金額數量小於硬幣的面額,那這枚硬幣就不須要使用。好比找零金額爲6角,那1元的硬幣確定是用不着的。
一、2 兩個邊界條件在找零錢前應該是默認成立的,因此在編寫程序的時候須要將它們設置爲初始條件。
邊界條件3則是在咱們找零過程當中須要進行判斷的,在編程時候應該寫在找零程序中。
好了,說了這麼多,仍是直接上代碼方便快捷= =
package com.lkb.dp.problems; import java.util.Arrays; /** * @Description 硬幣找零問題 * 假設只有 1角,2角,5角,1元的硬幣, * 在超市結帳時,若是須要找零錢,收銀員但願將最少的硬幣數找給顧客。那麼,給定須要找的零錢數目,如何求得最少的硬幣數呢? * @Author lkb * @CreateDate: 2019/6/1 */ public class ChargeProblem { public static void main(String[] args) { int[] coinsValues = {1,2,5,10}; Arrays.sort(coinsValues); int n = 6; int minCoinsNumber = charge(coinsValues, n); System.out.println(minCoinsNumber); } /** * 功能描述: 硬幣找零問題 * @author lkb * @date 2019/6/1 * @param * @return int */ public static int charge(int[] coinKind, int money){ //這個數組保存最優解 //例如 value[2][5] 表示 使用 coinKind[0] coinKind[1] coinKind[2] 找零 money = 5 的最優解 int[][] value = new int[coinKind.length+1][money+1]; //邊界條件1:若是硬幣類型爲0,則永遠找不到合適的硬幣找零 、 // 這裏設置爲最大值是由於咱們後續比較使用 for(int i=0; i<=money; i++){ value[0][i] = Integer.MAX_VALUE; } //邊界條件2:若是錢爲0,則永遠找不到合適的硬幣找零 for(int i=0; i<=coinKind.length; i++){ value[i][0] = 0; } for(int mon=1; mon<=money; mon++){ for(int kind=1; kind<=coinKind.length; kind++){ //邊界條件2:若是硬幣金額大於錢,則最優解是 上一步的最優解 if(coinKind[kind-1] > mon){ value[kind][mon] = value[kind-1][mon]; continue; } //當前最優解分爲兩種狀況,須要在下面兩種狀況選擇一種解最小的狀況 //一個是使用了當前類型的硬幣,value[kind][mon - coinKind[kind-1]] + 1 // 一個是沒有使用當前類型的硬幣, value[kind-1][mon] if((value[kind][mon - coinKind[kind-1]] + 1) < value[kind-1][mon]){ value[kind][mon] = value[kind][mon - coinKind[kind-1]] + 1; }else{ value[kind][mon] = value[kind-1][mon]; } } } return value[coinKind.length][money]; } }
你們也能夠在這個地址下載源碼,或者關注個人公衆號,一塊兒見證個人成長。