zoukankan      html  css  js  c++  java
  • 算法学习——动态规划讲解

    一、概念

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

    二、题型特点

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

    三、如何使用动态规划

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

    题目链接LeetCode-322

    Coin Change

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

    示例

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

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

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

    3.1 组成部分一:确定状态

    确定状态需要有两个注意的点:最后一步子问题

    1.最后一步

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

    由于是最优解,则11-(a_k)的硬币数一定是最少。

    2.子问题

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

    那么(a_k)到底是多少,因为有3枚硬币,所以只可能是1、2、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 组成部分四:计算顺序**

    从上到下,从左到右。

    四、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动态规划
    算法数据结构面试通关(经验全集)

  • 相关阅读:
    The Quad
    将OrCAD Capture CIS的设计文件(.dsn)导入到PADS Logic VX.2.3
    OrCAD Capture CIS 16.6 将版本16.6的设计文件另存为版本16.2的设计文件
    Eclipse IDE 添加jar包到Java工程中
    PADS Logic VX.2.3 修改软件界面语言
    切换Allegro PCB Editor
    Allegro PCB Design GXL (legacy) 将brd文件另存为低版本文件
    Allegro PCB Design GXL (legacy) 设置自动保存brd文件
    Could not create an acl object: Role '16'
    windows 下apache开启FastCGI
  • 原文地址:https://www.cnblogs.com/fonxian/p/10854654.html
Copyright © 2011-2022 走看看