动态规划算法

动态规划

什么是动态规划

简而言之,就是计算并存储小问题的解,并将这些解组成大问题的解。

动态规划解决步骤

1.确定状态:明确状态含义

2.确定转移公式:将状态间关系确定

3.确定边界条件:明确边界信息

4.计算结果

案例1:换零钱(凑出指定金额所需最少的硬币数)

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

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

解决

1.确定状态:设dp[i]表示金额为i时所需的最少硬币数。

2.确定转移公式:dp[i]表示金额为i时所需最少金额,假设选择金额为35,有1块,2块,5块以及10块4种硬币。那么现在选择1块钱问题就变为1+dp[34],选择2块钱问题就变为1+dp[33],选择5块钱问题就变为1+dp[30],选择10块钱问题就变为1+dp[25],其中1+代表现在已经使用了一个硬币,所以结果加1。而dp[35]就等于这4种情况的最小值。即dp[35]=min(1+dp[34],1+dp[33],1+dp[30],1+dp[25])。同样dp[34]也可安装刚才思路推理下去dp[34]=min(1+dp[33],1+dp[32],1+dp[29],1+dp[24])。由此可得出状态转移公式为 dp[n]=min(1+dp[n-coins[j]])

动态规划就是这样将大问题化解为小问题,并将小问题的解先存储起来,再计算大问题时用小问题的解一步一步化解出来。

3.确定边界条件:dp[0]即金额为0时所需硬币数,故dp[0]=0。当然还有可能永远也凑不出指定金额的情况,比如总金额为7,硬币种类为[2,10]。这样永远也凑不出7来。故需要设定一个值来判定是否凑不出

4.计算结果

  public int coinChange(int[] coins, int amount) {  
int []dp=new int[amount+1];
        int min=0;
        for (int i = 1; i <amount+1 ; i++) {
            dp[i]=amount+1;
        }
        for (int i = 0; i < dp.length; i++) {
            min=amount+1;
            dp[0]=0;
            for (int j = 0; j < coins.length; j++) {
                if(i>=coins[j]) {
                    dp[i] = 1 + dp[i - coins[j]];
                    dp[i] = Math.min(min, dp[i]);
                    min=dp[i];
                }
            }

        }
       return dp[amount]>amount?-1:dp[amount];
  }

解释:

定义数组dp来存储不同金额时所需最少硬币数。为确定总金额是否永远也凑不出所以预先初始化数组为除dp[0]外每项都为amount+1。这样如果最后结果大于amount说明此金额是凑不出的。

案例2:爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

**注意:**给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 1:

输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

解决

1.确定状态:使用数组dp[i]表示i阶楼梯有dp[i]种方式爬。

2.确定状态转移公式:爬上第i层楼梯有两种方案。1.从i-1层爬一层。2.从i-2层爬两层。同理爬上i-1层也有两种方式 1. 从i-2层爬一层,2.从i-3层爬2层。故可推到出关系为dp[i]=dp[i-1]+dp[i-2]。

3.明确边界条件:当i=1时只有一种dp[1]=1。当i=2时有两种,dp[2]=2。

4.计算结果

      public int climbStairs(int n) {
           int []dp=new int[n+1];
        if(n==1)return 1;
        if(n==2)return 2;
        dp[1]=1;
        dp[2]=2;
        for (int i = 3; i <=n ; i++) {
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值