贪心算法和动态规划

引言

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

总结

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

相关推荐
kaixin_啊啊26 分钟前
专用优化算法LKH
算法
一木 之林42 分钟前
四、STL容器与数据结构
开发语言·数据结构·c++
程与留1 小时前
07_QMainWindow 与应用程序框架——菜单栏、工具栏、状态栏
c++·qt
_Narcissus_2 小时前
二分算法笔记及例题
数据结构·c++·笔记·算法·蓝桥杯·查找·二分算法
tachibana22 小时前
RAGAS 指标解读
数据库·人工智能·算法·机器学习·架构·大模型·llm
qq_419563093 小时前
ToT 的 BFS/DFS 有个致命缺口:蒙特卡洛树搜索(MCTS)用「随机试错+统计」让大模型想得更深,小模型 + 它竟超过 GPT-4
算法·深度优先·宽度优先
万法若空3 小时前
CSP-J/S 排序算法完整专题训练题单
数据结构·算法·排序算法
凉茶钱3 小时前
【数据结构】排序(快排,选择,直接插入,希尔)
数据结构·算法·排序算法
weixin_446260854 小时前
拆解再复用:大模型智能体的跨任务技能迁移
人工智能·深度学习·算法
Brilliantwxx4 小时前
【Linux】 进程(4)七大进程状态深度解析
linux·运维·算法