代码随想录算法训练营第四十五天| 动态规划

Posted by Zhuoqun on February 27, 2023

70. 爬楼梯 (进阶)

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n + 1];
        int[] weight = {1,2};
        dp[0] = 1;

        for (int i = 0; i <= n; i++) {
            for (int j = 0; j < weight.length; j++) {
                if (i >= weight[j]) dp[i] += dp[i - weight[j]];
            }
        }

        return dp[n];
    }
}

322. 零钱兑换

这道题自己没做出来,但是思路理解了。

因为是并不是每个零钱只能用一次,所以遍历零钱的循环放在里外都可以。

这道题有几个难点要想通:

  1. 为什么取dp[i - coins[j]] + 1和 dp[i] 的最小值。取dp[i]的最小值好理解,dp[i - coins[j]] + 1的意思是当前如果amount是7,coin遍历到了5,那么能凑成的组合数就是 如果amount是2时候也凑成了组合数,那么目前的coin到了5 也就是在2的组合数基础上加上coin5,所以就是加了一个币,那就是+1。(要强调的是dp的含义是最少多少个币凑成当前需要的数)
  2. 要把dp数组的数初始化为INT_MAX,也就是最大值。这样的话才可以比较min。如果都初始化为0的话,那么比较每个数的最小值的时候就没有效果了。另外也要保证遍历的时候,dp[i - coins[j]] 也要不能是INT_MAX,因为如果结果是INT_MAX,那说明dp[i - coins[j]]没能凑出个组合来。
  3. 最后的dp[amount]如果是初始值,也就是INT_MAX,说明就是没找到任何一个coin的组合来凑成所需的amount。
    class Solution {
    public:
     int coinChange(vector<int>& coins, int amount) {
         vector<int> dp(amount+1,INT_MAX);
         dp[0] = 0;
    
         for(int i=1; i<=amount; i++){
             for(int j=0; j<coins.size(); j++){
                 if(coins[j] <= i  && dp[i - coins[j]] != INT_MAX){
                     dp[i] = min(dp[i - coins[j]] + 1, dp[i]);
                 }
             }
         }
         if (dp[amount] == INT_MAX) 
             return -1;
         return dp[amount];
     }
    };
    

279.完全平方数

思路是理解了,但是自己还是写不出来。想不出来递推公式。

class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n+1,INT_MAX);
        dp[0] = 0;
        for(int i=0; i<=n; i++){
            for(int j=1; j*j<=i; j++){
                if(dp[i-j] != INT_MAX)
                    dp[i] = min(dp[i],dp[i - j * j] + 1);
            }
        }
        return dp[n];
    }
};