贪心算法和动态规划

引言

738. 单调递增的数字 - 力扣(LeetCode)

96. 不同的二叉搜索树 - 力扣(LeetCode)

416. 分割等和子集 - 力扣(LeetCode)

代码

第一题

这一题的思路就是我们从最后面开始向前遍历,找到第一个开始不符合单调递增的数字,然后把那个数据进行一个标记,同时-1,因为我们都知道,这个数后面的所有数都要变成9,因为可以保证递增的前提下数是最大的,但是如果这个数不-1,那么更新后的数一定比本数据要大。

cpp 复制代码
class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string strNum = to_string(n);
        int flag = strNum.size();
        for (int i = strNum.size() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i]) {
                flag = i;
                strNum[i - 1]--;
            }
        }
        for (int i = 0; i < strNum.size(); i++) {
            if (i >= flag) {
                strNum[i] = '9';
            }
        }
        return stoi(strNum);
    }
};

动态规划的思路

第一步:确定dp数组的含义,比如dpi表示的是第i个的。。。。

第二步:确定递推公式

第三步:初始化dp数组

第四步:确定遍历顺序

第二题

这一题我们先要明白dp的含义是当有n个结点的时候有多少种情况。我们要讨论二叉搜索树的情况,主要就是根节点的不同,不同的根节点就代表把一颗树分成了什么样,然后子树又继续分,所以我们可以很容易的想到,我们需要轮流遍历每个根节点,然后假设第j个是根节点的时候,左边又j - 1个结点,右边有i - j个结点,所以根据dp的含义,就有了递推公式dpi += dpj - 1 * dpi - j

cpp 复制代码
class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1, 0); // n个结点的数量
        dp[0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        return dp[n];
    }
};

01背包

dpij的含义是我们处理从第一个物品到第i个物品,这个时候背包的承受量是j,此时最大的价值是多少。

二维数组

先遍历物品

cpp 复制代码
// 先遍历物品
for (int i = 1; i < weight.size(); i++) {
    for(int j = 0; j <= bagWeight.size(); j++) {
        if (weight[i] > j) {
            dp[i][j] = dp[i - 1][j];
        } else {
            dp[i][j] = max(dp[i][j - weight[i]] + value[i], dp[i - 1][j]);
        }
    }
}

先遍历背包容量

cpp 复制代码
// weight数组的大小 就是物品个数
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
    for(int i = 1; i < weight.size(); i++) { // 遍历物品
        if (j < weight[i]) dp[i][j] = dp[i - 1][j];
        else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    }
}

一维数组

cpp 复制代码
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

第三题

这一题我们很难想到是用01背包来写的,我们用01背包来写的思路是因为数组的和可以分成两个部分,那么把和分成两半,target就是背包的容量。这里的dpj表示容量为j的背包最大价值是多少,因为这里重量和价值是一样的,所以我们只需要判断容量为target的时候价值最大是不是target,然后也不需要担心会不会有numsi比target还要大,因为我们有j >= numsi在兜底,可以保证我们每一次的背包都不会超重。

cpp 复制代码
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for (int i = 0; i < nums.size(); i++) {
            sum += nums[i];
        }
        if (sum % 2 != 0) {
            return false;
        } 
        int target = sum / 2;
        vector<int> dp(1000000, 0);
        for (int i = 0; i < nums.size(); i++) {
            for (int j = target; j >= nums[i]; j--) {
                dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
            }
        }
        if (target == dp[target]) {
            return true;
        }
        return false;
    }
};

总结

本篇文章到这里就结束了!!!希望可以帮助大家理解~~~~

相关推荐
程序喵大人4 小时前
【C++入门】编译链接模型 - 01 一个 C++ 程序是怎样变成可执行文件的
开发语言·c++·编译链接模型
奋发向前wcx4 小时前
CSP-J复赛模拟赛4 王晨旭补题 2026.10.5
算法
by209995 小时前
vector 的模拟实现:扩容与边界的详细阐述(下)
c++·经验分享·vector·动态数组
念何架构之路7 小时前
zap采样器与性能优化内幕
算法·性能优化·哈希算法
晒太羊的猫8 小时前
hot100动态规划刷题
算法·动态规划
weixin_531094698 小时前
heap_4内存管理
java·开发语言·算法
余额瞒着我当琳8 小时前
红黑树的实现--红黑树的概念、规则、效率、结构、旋转、查找、验证
数据结构·c++·算法
程序员南飞8 小时前
win系统安装minio
java·数据结构·算法
青少儿编程课堂8 小时前
AC自动机多模式串匹配精讲:校园关键词巡检实战解析
c++·python·算法·bfs·信息学竞赛
longlongzihan9 小时前
LeetCode 5. 最长回文子串:从暴力匹配到中心扩展的思维演进
c++·算法·leetcode