博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法之动态规划
阅读量:5157 次
发布时间:2019-06-13

本文共 3690 字,大约阅读时间需要 12 分钟。

动态规划

2.个人理解

个人感觉这是一种由最简单的状态推得复杂的状态的算法,相较于编程更是一种数学思想,用来解决存在相同子问题的时候求最优,缓存前一个状态的结果,避免重复计算。

3.硬币找零应用动态规划

假设有几种硬币,并且数量无限。请找出能够组成某个数目的找零所使用最少的硬币数。

硬币数量无穷大,硬币种类未知,求最少,存在找零时多种硬币面值使用与否 看上去像是动态规划可以解决的问题

抛开算法的概念,用数学的思想列出来一些结果找规律,假设硬币面值为2,3,5

列出表

 表内容每一项为硬币数量

硬币面值/找零金额   0    1    2    3    4    5    6    7    8    9    10 2                INF  INF   1   INF   2   INF   3   INF   4   INF   5 3                INF  INF   1    1    2    2    2    3    3    3    4 5                INF  INF   1    1    2    1    2    2    2    3    2 INF表示找不到

去掉表内重复内容

硬币面值/找零金额   0    1    2    3    4    5    6    7    8    9    10只使用2找零       INF  INF   1   INF   2   INF   3   INF   4   INF   5使用2,3找零                       1    2    2    2    3    3    3    4使用2,3,5找零                               1    2    2    2    3    2 INF表示找不到

单从这十项可以得到这样的一个结论:

当使用的最大硬币面值小于找零面值时,

其找零所需的硬币数与不使用这种硬币找零所需的硬币数相同,因为该种硬币太大,比如使用2,3面值的硬币给4找零时,使用面值为3的硬币不能给面值为4的钱换零,只能用两个面值为2的硬币找零。

同时,如果找零使用的最大硬币面值大于等于找零金额,其所使用的硬币总数总是小于等于不使用此种硬币时的数量。从表中的数据得出其所使用的硬币数量为 (找零金额-最大硬币面值)所需的硬币数量+1(最大面值硬币数量)。

如果用数组按从小到大的顺序进行存储的话得到:

int[] coins = new int[]{2,3,5};

 可以列出这样的一个方程:

当j<coins[i]      f(i,j)=f(i-1,j);                                              

当j>=coins[i]    f(i,j)=Integer.min(1+f(i,j-coin[i]),f(i-1,j));   由于存在找零金额为4,硬币面值使用2,3时 使用一张3面值的硬币进行找零,余一个值为1的面值,没有硬币面值能兑现这个余数的情况,所以还要与使用2对4进行找零的情况进行比较得出合理的结果

 i表示使用的最大硬币面值,j表示找零金额

由于每增加使用一种硬币,存在重复的硬币数量和不符合要求的数量

如表中找零金额为6的列

硬币面值/找零金额  6
只使用2找零       3 使用2,3找零       2

只使用硬币面值为2的进行找零时使用3个硬币

使用2,3找零时使用2个硬币

求最少,需要用2替换掉3

可以用一个一维数组存储,从找零金额为0推算出只使用最小面值的硬币时所需的硬币数

方便视觉效果再贴上上面的数据

硬币面值/找零金额   0    1    2    3    4    5    6    7    8    9    10只使用2找零       INF  INF   1   INF   2   INF   3   INF   4   INF   5使用2,3找零                       1    2    2    2    3    3    3    4使用2,3,5找零                               1    2    2    2    3    2 INF表示找不到
硬币面值/找零金额   0    1    2    3    4    5    6    7    8    9    10只使用2找零       INF  INF   1   INF   2   INF   3   INF   4   INF   5

伪代码:定义数组int[] dp = new int[11]{INF,INF,1,INF,2,INF,3,INF,4,INF,5};

当加入硬币面值为3时

硬币面值/找零金额   0    1    2    3    4    5    6    7    8    9    10使用2,3找零                       1    2    2    2    3    3    3    4

替换掉dp中较大的值

dp = {INF,INF,1,1,2,2,2,3,3,3,4}

方程可以修改为:                                             

当j>=coins[i]    f(j)=Integer.min(1+f(j-coin[i]),f(j));   由于存在找零金额为4,硬币面值使用2,3时 使用一张3面值的硬币进行找零,余一个值为1的面值,没有硬币面值能兑现这个余数的情况,所以还要与使用2对4进行找零的情况进行比较得出合理的结果

 此时,动态规划的三大分析条件

1.最优子结构  我未分析出

2.边界 0

3.状态转移方程 为上面的修改后方程

 

4.我的Java代码实现

/**     * @param coins 零钱面值数组     * @param n     需要被找零的钱     */    public int coinForChange(int[] coins, int n) {        //排序从小到大        Arrays.sort(coins);        //找零的钱比最小零钱都小 找不开        if (n < coins[0]) {            return -1;        }        int coinsKind = coins.length;        //定义第一种零钱面值 0-n面额下找零硬币数量数组        int[] dp = new int[n + 1];        //余数 标记只使用最小面值硬币是否可以找零        int remainder;        int value;        //初始化找零数量 0-n计算找零所需硬币 找不开使用Integer的最大值表示 即上表中INF        for (int i = 0; i < dp.length; i++) {            remainder = i % coins[0];            //找不开时 使用找零钱币为最大表示            dp[i] = remainder == 0 ? i / coins[0] : Integer.MAX_VALUE;        }        //从加入第二种零钱面值 开始循环到第i种零钱面值        for (int i = 1; i < coinsKind; i++) {            //加入的该种零钱金额比找零的总额大的,该找零钱币数量与上一次循环得到的结果相同            for (int j = coins[i]; j < dp.length; j++) {                value = 1 + dp[j - coins[i]];                //若最小面值不能找开零钱时为2^31 - 1                //+1后int型溢出为负数 此时扔找不开 重新赋值为最大                value = value >= 0 ? value : Integer.MAX_VALUE;                dp[j] = Integer.min(value, dp[j]);            }        }        return dp[n];    }

最近在刷leetcode学习算法,经常遇到动态规划解决的问题,之前忽略了刷leetcode的目的,为刷题而刷题,每次遇到都需要花功夫理解程序,这几天忽然醒悟,研究算法解决问题,理解还是很浅,如果有错误或模糊不清的地方请各位大佬指教。

转载于:https://www.cnblogs.com/DaMoGu/p/10879791.html

你可能感兴趣的文章
javascript 无限分类
查看>>
spring IOC装配Bean(注解方式)
查看>>
[面试算法题]有序列表删除节点-leetcode学习之旅(4)
查看>>
kubernetes_book
查看>>
侧边栏广告和回到顶部
查看>>
https://blog.csdn.net/u012106306/article/details/80760744
查看>>
海上孤独的帆
查看>>
处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“Manag
查看>>
01: socket模块
查看>>
mysql触发器
查看>>
淌淌淌
查看>>
win10每次开机都显示“你的硬件设置已更改,请重启电脑……”的解决办法
查看>>
C++有关 const & 内敛 & 友元&静态成员那些事
查看>>
函数积累
查看>>
Swift 入门之简单语法(六)
查看>>
〖Python〗-- IO多路复用
查看>>
栈(括号匹配)
查看>>
Java学习 · 初识 面向对象深入一
查看>>
源代码如何管理
查看>>
vue怎么将一个组件引入另一个组件?
查看>>