LeetCode题解之动态规划(二)

220 阅读1分钟

1.背包dp基本方法

背包问题的各种类型,基本上是给一堆物品和体积、个数的限制,要求价值最大,有个别基于同样背景下却求数值的题

分类:
01背包:每件物品放或不放
多重背包:每件物品有限个
完全背包:每件物品无限个
分组背包:一组中只能选一件物品
纬度:
最好理解的是f[i][j],但视情况可以用滚动数组优化到一纬

完全背包题目

322. 零钱兑换

class Solution {
public:
    int coinChange(vector<int>& coins, int m) {
        int n = coins.size();
        int init = m + 1;//初始化成一个大的数
        vector<int> f(m + 1, init);
        f[0] = 0;
        for(int i = 1; i <= n; i ++)
            for(int j = coins[i - 1]; j <= m; j ++)
                f[j] = min(f[j], f[j - coins[i - 1]] + 1);//min的完全背包
        return f[m] != init ? f[m] : -1;//判断是否能凑够
    }
};

518. 零钱兑换 II

class Solution {
public:
/*
1.状态表示:f[n][m],硬币种类[0,n-1],对应[1,n],金额总数[1,m]对应[1,m]
2.状态属性:数值
3.状态转移:f[i][j]代表从前i种硬币中选,金额为j的方法数,转移为f[i][j] =  f[i - 1][j]+(满足条件)f[i][j - coins[i - 1]]
*/
    int change(int m, vector<int>& coins) {
        int n = coins.size();
        vector<int> f(m + 1, 0);
        f[0] = 1;//初始化
        for(int i = 1; i <= n; i ++)
            for(int j = coins[i - 1]; j <= m; j ++)
                f[j] += f[j - coins[i - 1]]; 
        return f[m];
    }
};

剑指 Offer 60. n个骰子的点数

class Solution {
public:
/*
1.状态表示:f[n][m],投的硬币数[0,n-1],对应[1,n],点数总数[1,m]对应[1,m]
2.状态属性:数值
3.状态转移:f[i][j]代表从前i个骰子中选,点数和为j的方法数。枚举第i个骰子投出的点数1-min(j,6),则f[i][j] += f[i-1][j-k]
*/
    vector<double> twoSum(int n) {
        vector<vector<int>> f(n + 1,vector<int>(n * 6 + 1, 0));
        f[0][0] = 1;
        for(int i = 1; i <= n; i ++)
            for(int j = 1;j <= i * 6; j ++)
            {
                for(int k = 1;k <= min(6,j);k ++)//用的骰子点数最多为:min(j,6)
                    f[i][j] += f[i-1][j-k];
            }
        vector<double> res;
        for(int i =n; i <= 6 * n; i ++) res.push_back(f[n][i]);
        int s = 0;
        for(int i = 0;i < res.size();i ++) s += res[i];
        for(int i = 0;i < res.size(); i ++) res[i] /= s;
        return res;
    }
};

279. 完全平方数

class Solution {
public:
/*
完全背包问题
*/
    class Solution {
public:
/*
完全背包问题
*/
    int numSquares(int n) {
        vector<int> choices;
        int i = 1;
        while(i <= n / i)//i*i <=n
        {
            choices.push_back(i * i);
            i ++;
        }
        int m = choices.size();//物品个数
        int init = n + 1;
        vector<int> f(n + 1, init);
        f[0] = 0;
        for(int i = 1; i <= m; i ++)
            for(int j = choices[i - 1]; j <=n; j ++)
                f[j] = min(f[j], f[j - choices[i - 1]] + 1);
        return f[n];

    }
};

部分内容来自y总的教学,致谢!