算法学习——动态规划讲解

1、概念

经过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划经常适用于有重叠子问题和最优子结构性质的问题。html

2、题型特色

  • 计数
    • 有多少种方式走到最右下角
  • 求最大值最小值
    • 从左上角走到右下角的最大数字和
  • 求存在性
    • 可否选出k个数使得和为sum

3、如何使用动态规划

这里先看一道LeetCode题。从这道题来学习如何使用动态规划。java

题目连接LeetCode-322面试

Coin Change算法

给定不一样面额的硬币 coins 和一个总金额 amount。
编写一个函数来计算能够凑成总金额所需的最少的硬币个数。
若是没有任何一种硬币组合能组成总金额,返回 -1。

示例数据结构

输入: coins = [1, 2, 5], amount = 11
输出: 3 
解释: 11 = 5 + 5 + 1

该题是一个求最大最小的动态规划算法题。ide

与递归解法相比,没有重复计算。函数

3.1 组成部分一:肯定状态

肯定状态须要有两个注意的点:最后一步子问题学习

1.最后一步spa

确定是$k$枚硬币加起来等于11。最后一枚硬币值假设是$a_k$,则剩下的$k-1$枚硬币的值为$11-a_k$。code

因为是最优解,则11-$a_k$的硬币数必定是最少。

2.子问题

将原问题转换为子问题,最少用多少枚硬币拼出$11-a_k$

那么$a_k$究竟是多少,由于有3枚硬币,因此只多是一、二、5中的一个。

子问题方程以下:

$f(11) = min{f(11-1)+1,f(11-2)+1,f(11-5)+1}$

f(11)为拼出面值为11所需的最少硬币数。

根据以上,使用递归的解法:

public class Dp1 {

    public int getMinCoin(int X) {

        if (X == 0) return 0;
        int res = 10000;
        if (X >= 1) {
            res =  Math.min(getMinCoin(X - 1)+1, res);
        }
        if (X >= 2) {
            res =  Math.min(getMinCoin(X - 2)+1, res);
        }
        if (X >= 5) {
            res =  Math.min(getMinCoin(X - 5)+1, res);
        }
        return res;
    }

    public static void main(String[] args) {
        Dp1 dp1 = new Dp1();
        int result = dp1.getMinCoin(11);
        System.out.println(result);
    }

}

在这里插入图片描述 使用递归来解决,有比较多的重复计算,效率比较低。

动态规划会保存计算结果,来避免递归重复计算的问题。

3.2 组成部分二:转移方程

动态规划的解法

状态f[X]表示,面值为X所需的最小硬币数。 对于任意的X,知足 $f[X] = min{f[X-1]+1,f[X-2]+1,f[X-5]+1}$

意思就是获取面值大小为X最少须要的硬币数 = 从(最后一个硬币选1时,剩下的要凑面值为X-1所须要的最少硬币数,由于最后一个硬币选了1,因此硬币数要+1,即f[x-1]+1)、(f[X-2]+1)、(f[X-5]+1)中选择一个最少的硬币数。

3.3 组成部分三:初始条件和边界状况

设置初始值,考虑边界状况。

3.4 组成部分四:计算顺序**

从上到下,从左到右。

4、LeetCode题完整解法

class Solution {
    public int coinChange(int[] coins, int amount) {
        
        int[] f = new int[amount+1];
        int coin_num = coins.length;
        //初始条件
        f[0] = 0;
        //f[x] = min{f[x-c1]+1,f[x-c2]+1,f[x-c3]+1}
        for(int x = 1;x<=amount;x++){
            f[x] = Integer.MAX_VALUE;
            for(int i = 0;i<coin_num;i++){
                // 考虑输入[2],4,则须要保证f[x-coins[i]] != Integer.MAX_VALUE,即f[x-coins[i]]必需要是存在的状态
                if(x >=coins[i] && f[x-coins[i]] != Integer.MAX_VALUE){
                    f[x] = Math.min(f[x-coins[i]]+1,f[x]);
                }
            }
        }
        // 考虑输入[2],3,则amount = -1
        if(f[amount] == Integer.MAX_VALUE){
            return -1;
        }
        return f[amount];
    }
}

参考文档

动态规划

参考视频

动态规划入门 Introduction to Dynamic Programming ACM专题讲解:DP动态规划 算法数据结构面试通关(经验全集)

相关文章
相关标签/搜索