找零问题

找零问题:
对于一种货币,有面值c1,c2,....,cN的硬币,最少需要多少个硬币来找出K分钱的零钱。硬币面值中总是有面值为1的硬币。
第一行输入一组数据表示硬币面值,用空格分割,第二行输入要找的K分钱
输入数据:
1 5 10 21 25
63
输出数据:
3

看到这道题的瞬间,我是只想到了穷举算法(捂脸),所以想出了下面这样的写法:

 1 public class MakeChange {
 2 private static int min = Integer.MAX_VALUE;
 3 /**
 4 * @param coins 硬币数组
 5 * @param k    要找的零钱k
 6 * @param count 当前所用的硬币数
 7 * @return
 8 */
 9 public static void take_change(int[] coins,int k,int count){
10 if(k<0){
11 return;
12 }
13 if(k==0){
14 if(min>count)
15 min = count;
16 }
17 for(int coin:coins){
18 take_change(coins,k-coin,count+1);
19 }
20 }
21 }
View Code


就是很普通的遍历硬币数组,然后每个硬币都试一下,当要找的零钱k等于0的时候,说明这次找到的是一次有效的组合,然后观察此时的硬币数量count跟当前最小值的硬币数量的大小关系,最后运算完毕min自然是需要的最少硬币数了。但这个算法的运行时间极其的长,光是运行测试样例中的数据就已经接近1s了,并且随着数组长度的增加,时间会增长的特别快,所以这个算法不可行~~~这个时间复杂度我不会算(苦笑)

这时,回归题目本身,我试图从从微小的例子中看有木有规律,于是做了下面这张表:
硬币数组: 1 5 10 21 25
要找零的零钱:1 2 3 4 5
硬币数: 1 2 3 4 1
发现手工运算中,在要找的零钱为5时发生了变化,因为硬币数组里面有5这个面值,那么,如果以dp[i]表示找1分钱需要的最少的硬币数,那么在i=5时(即要找的零钱数为5),其实是隐含了dp[5] = min(dp[5-1]+1,dp[5-硬币数组中的面值]+1,这个算式的,抽象一下就是:
dp[i] = min(dp[i-1]+1,dp[i - for i in coins]+1)
解释一下意思,找i元零钱最少需要的硬币=min(找i-1元零钱最少需要的硬币+1枚硬币(相当于增加了一枚一元硬币),找i-coin元零钱最少需要的硬币+1,其中coin为可用的硬币面值,注意i-coin可能是负数)
因此,只需要从0元零钱一直递推到题目需求的k元零钱就能解决问题,时间复杂度为O(AN),其中A是数组的长度,严格来说其实就是O(N)
代码如下:

 1     public static void main(String args[]) throws NumberFormatException, IOException{
 2         BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
 3         String num = in.readLine();
 4         int length = Integer.parseInt(num);
 5         String[] str = in.readLine().split(" ");
 6         int[] coins = new int[str.length];
 7         for(int i=0;i<coins.length;i++){
 8             coins[i] = Integer.parseInt(str[i]);
 9         }
10         
11         for(int i=0;i<coins.length;i++){
12             System.out.println("coins["+i+"]"+coins[i]);
13         }
14         int[] dp = new int[length+1];
15         dp[0] = 0;
16         for(int i=1;i<=length;i++){
17             int min = dp[i-1]+1;
18             for(int coin:coins){
19                 if(i-coin>=0){
20                     min = Math.min(min, dp[i-coin]+1);
21                 }
22             }
23             dp[i] = Math.min(dp[i-1]+1,min);
24         }
25         System.out.println(dp[length]);
26     }


写的不太好请读者们见谅~~~目前还在努力学习技术和增强自己的表达方式中,想通过写文章来锻炼自己~~~

原文地址:https://www.cnblogs.com/sword-magical-blog/p/7476115.html