贪心算法和动态规划

引言

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;
    }
};

总结

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

相关推荐
happyprince1 小时前
篇3:bitsandbytes-深刻观-哲学与升华
人工智能·算法
我不是懒洋洋1 小时前
从零实现一个分布式数据集成:Airbyte的核心设计
c++
应用市场1 小时前
红绿灯背后的算法:从 Webster 配时到 Max-Pressure 与强化学习
算法
用户0510122572961 小时前
DAY 5-智能指针与 C++ 内存管理
c++·面试
木井巳1 小时前
【DFS解决floodfill算法】岛屿的最大面积
java·算法·leetcode·深度优先
(Charon)1 小时前
【C++】手写 MySQL 连接池(三):异步任务队列与工作线程
c语言·c++
yyds_yyd_100862 小时前
877. 石子游戏(2026.08.02)& 486. 预测赢家(2026.08.01)
c++·leetcode
小小帅呀2 小时前
CUDA编程实战12:原子操作与高性能直方图——从正确累加到低冲突并行更新
c++·人工智能·线性代数·矩阵
加油码2 小时前
共享内存详解:原理、系统调用与高性能进程间通信
linux·c语言·c++