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

一、概念

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

二、题型特点

  • 计数
    • 有多少种方式走到最右下角
  • 求最大值最小值
    • 从左上角走到右下角的最大数字和
  • 求存在性
    • 能否选出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\}\)

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++){
                if(x >=coins[i] && f[x-coins[i]] != Integer.MAX_VALUE){
                    f[x] = Math.min(f[x-coins[i]]+1,f[x]);
                }
            }
        }
        if(f[amount] == Integer.MAX_VALUE){
            return -1;
        }
        return f[amount];
    }
}

参考文档

动态规划

参考视频

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

猜你喜欢

转载自www.cnblogs.com/fonxian/p/10854654.html
今日推荐