zoukankan      html  css  js  c++  java
  • 找零问题

    找零问题:
    对于一种货币,有面值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     }


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

  • 相关阅读:
    mysql通过一张表更新另一张表
    申请微信支付填错对公账号的解决办法
    radio 实现点击两次 第一次点击选中第二次点击取消
    C#修改下拉框选项的高度
    Centos7 用yum命令安装LAMP环境(php+Apache+Mysql)以及php扩展
    php备份数据库
    windows环境下 composer 的安装与使用
    PHP获取多维数据的交集与差集
    JS 图片懒加载
    搭建 window + nginx + php 开发环境
  • 原文地址:https://www.cnblogs.com/sword-magical-blog/p/7476115.html
Copyright © 2011-2022 走看看