硬币问题 动态规划_动态规划

硬币问题 动态规划_动态规划动态规划-硬币问题分析

大家好,又见面了,我是你们的朋友全栈君。

什么是动态规划

上次对动态规划已经有了个大概的分析。引用维基百科的话就是:
dynamic programming is a method for solving a complex problem by breaking it down into a collection of simpler subproblems

翻译过来就是动态规划就是通过拆分问题,来解决复杂的问题的一个方式。所以我们也知道,动态规划的核心就是如何取拆分这个问题那如何拆分问题,这个也就成为我们要去研究的重点。借鉴于大部分权威人士比较认同的观点是:拆分问题,靠的是状态的定义和状态转移方程的定义。
这里有一遍知乎是对上面的定义的见解:www.zhihu.com/question/23…

什么是状态的定义

我们对状态的定义是这样的:解答动态规划问题,需要开一个数组,数组中的每一个元素f[i]或f[i][j]代表了什么。而状态的定义需要两个步骤:
1.最后一步;
2.子问题。

题目描述

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

Example Given coins = [1, 2, 5], amount = 11 return 3 (11 = 5 + 5 + 1)

Given coins = [2], amount = 3 return -1.

Notice You may assume that you have an infinite number of each kind of coin.

问题简单解释:现有不同币值的硬币,凑足一个给定的金额,不能多不能少,得出最少的硬币个数;如果无解,返回-1。

解题思路

那我们重新返回之前说的状态的定义的两个步骤。
最后一步:

我们就从例子里面说的,有1,2,5三个币值的硬币,凑足11块。我们假设最优策略是k个硬币凑足了11块,最后的一块硬币币值是a(K)元,则前面的硬币拼出的币值为11-a(K)元,这就是先着手最后一步的状态定义。
然后从子问题讲:
由于我们已经从最后一步定义,将原问题转化成另外一个问题是用最少的硬币凑足11-a(K)元,此时将原规模变小,而此时的问题就是原问题的子问题。可以将凑足多少元(即规模)定义为X,则可以用状态f(X) = 用最少的硬币凑足X元。我们假设最后一枚硬币是1,则f(11) = f(11 -1)+1枚;最后一枚是2,则f(11) = f(11-2)+1枚;同理,最后一枚为5,则f(11)=f(11-5)+1枚,即其实最少的硬币为f(11)=min{f(11-1)+1,f(11-2)+1,f(11-5)+1}。 我们可以用程序进行表示:

// 递归解法 
// 没有考虑边界问题
伪代码
int f(x){
if(x==0)return 0;
int res = Integer.MAX_VALUE;
if(x>=1){
res = Math.min(f(x-1)+1,res);
}
if(x>=2){
res = Math.min(f(x-2)+1,res);
}
if(x>=5){
res = Math.min(f(x-5)+1,res);
}
return res;
}
复制代码

但递归法解法做了很多重复计算,比如f(9)->f(11-1)->f(10-9)或者f(11-2)计算可得。这时候我们可以从动态规划第二部分—状态的转移。

其实很简单将f(x) 变成一个数组f[x],将计算结果保存起来。此时函数f[x]=min{f[x-1]+1,f[x-2]+1,f[x-5]+1}。
由于是个数组,所以我们应该考虑下边界和初始值的问题。假设拼不出来的值如f[-1]或者f[-3]这种,我们定义为正无穷Max_Value,初始值f[0]=0代表要拼出0元即为0个硬币。此时我们应当从小到大顺序算出每个元素的最小硬币值,即:
f[1]=min{f[1-1]+1,f[1-2]+1,f[1-5]+1}=f[0]+1 = 1

f[2] = min{f[2-1]+1,f[2-2]+1,f[2-5]+1} = f[0]+1 = 1,

我们不难发现,当f[2]以1块为最后的硬币时,f[1]其实已经保存该值的最小硬币数,不会重复计算,且算法时间度是X*3

可以看下程序:

public int coinChange(int[] a, int M) {
        // write your code here
        int length = a.length;
        int []f = new int[M+1];

        // 初始化
        f[0]=0;
        for(int i=1;i<=M;i++){
            // 先将f[i]初始无穷大,进行对比
            f[i]= Integer.MAX_VALUE;
            for (int j=0;j<length;j++){
                // 凑足的金额一定得大于硬币的值且减了硬币不应该等于无穷大
                if(i>=a[j]&&f[i-a[j]]!=Integer.MAX_VALUE&&f[i-a[j]]+1<f[i]){
                    f[i]= f[i-a[j]]+1;
                }
            }
        }
        if(f[M]==Integer.MAX_VALUE){
            return -1;
        }else {
            return f[M];
        }
    }
复制代码

作者简介

考拉后端开发小哥Rowland,热爱运动还有点萌!

转载于:https://juejin.im/post/5ce7d44351882530810dfd1d

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/106808.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • java二维数组初始化(动态,静态)

    java二维数组初始化(动态,静态)int[][] a=new  int[][]{{1,2},{3,4},{5,6,7,8,9},{}};      System.out.println(a.length);//4,表示数组的行数      System.out.println(a[0].length);//2,表示对应行的长度      System.out.println(a[1].length);//2      System…

    2022年5月26日
    32
  • 小白 虚拟机 kali_Linux安装 详细教程「建议收藏」

    小白 虚拟机 kali_Linux安装 详细教程「建议收藏」安装版本:VMmareworkstationprokali_Linux安装环境:Window10首先我们先了解一下什么是kali_linux:KaliLinux是基于Debian的Linux发行版,设计用于数字取证操作系统。每一季度更新一次。由OffensiveSecurityLtd维护和资助。最先由OffensiveSecurity的MatiAharoni和DevonKearns通过重写BackTrack来完成,BackTrack是他们之前写的用于取证的Linux发行

    2022年4月30日
    76
  • docker容器获取宿主机IP「建议收藏」

    docker容器获取宿主机IP「建议收藏」1.bridge模式启动.通过环境变量–envHOST_IP=xxxx,通过环境变量$HOST_IP获取将主机/proc目录挂载到容器中(未验证)2.host模式启动通过iproute获取

    2022年8月21日
    11
  • spring整合Mybatis-plus[通俗易懂]

    spring整合Mybatis-plus[通俗易懂]spring整合Mybatis-plus今天就随便说说spring整合mybatis-plus,就不再搭建一个web项目了,简单做一个测试类。既然是spring,那就少不了各种xxx.xml配置文件。那就先说说配置文件<1>.application-dao.xmldao层的配置,他的核心就是要产生Mapper代理对象 1、数据源的配置<context:prope…

    2022年6月6日
    24
  • 微信公众平台应用开发实战「建议收藏」

    微信公众平台应用开发实战「建议收藏」微信公众平台应用开发实战微信营销ISBN 9787111438618作者 钟志勇含税价59.0元税后51.3元增值税7.7元卓越价 40.7元(满49元免运费) 有货出版社 机械工业出版社出版日期 2013年08月28日版次 第1版印刷时间2013年08月29日印次第1次装帧平装纸张胶版纸页数 256页语种 

    2022年8月21日
    4
  • git和github gitlab的区别_gitlab和git区别

    git和github gitlab的区别_gitlab和git区别GitHub是在线代码仓库,全世界只有GitHub一家,大家把代码存储在人家的服务器上。Gitlab相当于小型的GitHub,你可以在本地搭建一个属于你自己的类似GitHub仓库,让小伙伴把代码存储在上面,这样代码只有你们几个人能看见,但是你要存在GitHub上,全世界都能看见git是一种版本控制系统,是一个命令,是一种工具gitlib是用于实现git功能的开发库github是一个基于git实现的在线代码仓库,包含一个网站界面,向互联网开放gitlab是一个基于git实现的在线代码仓

    2022年10月23日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号