代码随想录算法训练营第33天|322. 零钱兑换、279.完全平方数、139.单词拆分

LeetCode322

2025-03-06 19:01:34 星期四

题目描述:力扣322
文档讲解:代码随想录(programmercarl)322. 零钱兑换
视频讲解:《代码随想录》算法视频公开课:装满背包最少的物品件数是多少?| LeetCode:322.零钱兑换

代码随想录视频内容简记

这个题特殊的地方在要求的是最少的物品数量,和一零和有点像,一零和求的是最大的物品数量

梳理

  1. 确定dp[j]数组的含义,表示背包容量为j装满所能放的最少物品数量为dp[j]

  2. 确定递推公式,dp[j] = min(dp[j], dp[j - coins[i]] + 1)。解释一下dp[j - coins[i]] + 1的含义,和一零和的dp[i - x][j - y] + 1很像,coins[i]表示重量,+ 1是因为dp数组表示物品的数量,一次只能+1

  3. 初始化dp[j]数组,dp[0] = 0表示背包容量为j所能放的最少物品数量为0,是符合题意的。另外,对于非零下标,因为本题求的是最小的min,所以后面初始化不能直接用0,而应该用INT_MAX

  4. 确定遍历顺序,首先和474一零和不一样的地方就在于本题是一个完全背包问题,所以对先遍历物品或者先遍历背包所求的一个是组合数,一个是排列数。但是因为本题所求的是最少的物品数量,和具体的组合方法个数不一样,所以那种遍历方式都可以

  5. 打印dp数组

LeetCode测试

点击查看代码
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<uint64_t> dp(amount + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i < coins.size(); i++) {
            for (int j = 0; j <= amount; j++) {
                if (j < coins[i]) dp[j] = dp[j];
                else dp[j] = min(dp[j], dp[j - coins[i]] + 1);
            }
        }
        if (dp[amount] == INT_MAX) return -1;
        return dp[amount];
    }
};

LeetCode279

题目描述:力扣279
文档讲解:代码随想录(programmercarl)279.完全平方数
视频讲解:《代码随想录》算法视频公开课:换汤不换药!| LeetCode:279.完全平方数

代码随想录视频内容简记

本题可以抽象为一个完全背包问题,首先整数n表示背包的最大容量为n,而每个物品的价值和重量都是一样的,可以像爬楼梯进阶那样进行先遍历写好其平方的数组

梳理

  1. 确定dp[j]数组的含义,表示容量为j的背包装满需要的最少物品数量为dp[j]

  2. 确定递推公式,和上面的322一样,dp[j] = min(dp[j], dp[j - nums[i]] + 1)

  3. 初始化dp数组,dp[0] = 0,剩余非零下边的值都初始化最大INT_MAX

  4. 确定遍历顺序,先遍历物品或者先遍历背包都可以

  5. 打印dp数组

LeetCode测试

刚开始写的是这样的,这样写的话数组定义那里总是出错,改成push_back就好了。

需要注意的是,在for循环遍历添加的时候,需要i * i <= n,因为有一个测试用例是n = 1,所以必须得加上等于号

点击查看代码
class Solution {
public:
    int numSquares(int n) {
        vector<int> nums;
        for (int i = 1; i * i <= n; i++) {
            nums.push_back(i * i);
            cout << i * i << endl;
        }
        cout << nums.size() << endl;
        vector<uint64_t> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i < nums.size(); i++) {
            for (int j = 0; j <= n; j++) {
                if (j < nums[i]) dp[j] = dp[j];
                else dp[j] = min(dp[j], dp[j - nums[i]] + 1);
            }
        }
        return dp[n];
    }
};

之后又看k哥的视频讲了一遍,思路都是一样的

点击查看代码
class Solution {
public:
    int numSquares(int n) {
        vector<uint64_t> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 1; i * i <= n; i++) {
            for (int j = 0; j <= n; j++) {
                if (j < i * i) dp[j] = dp[j];
                else dp[j] = min(dp[j], dp[j - i * i] + 1);
            }
        }
        return dp[n];
    }
};

LeetCode139

题目描述:力扣139
文档讲解:代码随想录(programmercarl)139.单词拆分
视频讲解:《代码随想录》算法视频公开课:你的背包如何装满?| LeetCode:139.单词拆分

代码随想录视频内容简记

首先确定本题的背包容量就是s字符串的长度,而本题物品的价值就是true或者false,物品的重量就是每一个在字典当中的单词本身,比如“leet”和“code”这两个单词本身,而至于用i遍历,只是通过这样的数值截取来得到单词本身的手段。

梳理

  1. 确定dp[j]数组的含义,表示串长为j的字符串,其表示的dp[j]为true,也就是可以在wordset总被找到,这样才能拼接s字符串。感觉这个题挺抽象的,感觉这个dp数组的定义就不太好理解

  2. 确定递推公式,if (字串存在于集合中 && dp[i] == true) dp[j] = true,在递推公式中需要判断的有两个,一个是单词必须在wordset中能找到,另外就是前面的dp[i]为true,这样做的目的就是确保前面所有单个单词都已经被在wordset中找到了

  3. 初始化dp[j]数组,dp[0] = true,如果一旦dp[0]为false,那么后面的所有情况机会都变成false了。至于非零下标,全部初始化为false即可

  4. 确定遍历顺序,本题要求的是一个排列数,组成的单词才会不一样,比如“applepenapple”和“penappleapple”的组合都一样,但是二者属于不同的排列。所以需要先遍历背包,后遍历物品,这也是确保wordset中分割的单词能拼成目标s的前提

  5. 打印dp数组

LeetCode测试

点击查看代码
class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
        vector<bool> dp(s.size() + 1, false);
        dp[0] = true;

        // string wo = "applepen";
        // cout << "applepen" << wo.substr(5, 3);


        for (int j = 0; j <= s.size(); j++) {// 先遍历背包
            for (int i = 0; i < j; i++) {// 再遍历物品
                string word = s.substr(i, j - i);
                if (wordSet.find(word) != wordSet.end() && dp[i] == true) dp[j] = true;
            }
        }
        return dp[s.size()];
    }
};
posted on   bnbncch  阅读(294)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示