算法沉淀——动态规划之其它背包问题与卡特兰数(leetcode真题剖析)

在这里插入图片描述

算法沉淀——动态规划之其它背包问题与卡特兰数

  • 二维费用的背包问题
    • 01.一和零
    • 02.盈利计划
  • 似包非包
    • 组合总和 Ⅳ
  • 卡特兰数
    • 不同的二叉搜索树

二维费用的背包问题

01.一和零

题目链接:https://leetcode.cn/problems/ones-and-zeroes/

给你一个二进制字符串数组 strs 和两个整数 mn

请你找出并返回 strs 的最大子集的长度,该子集中 最多m0n1

如果 x 的所有元素也是 y 的元素,集合 x 是集合 y子集

示例 1:

输入:strs = ["10", "0001", "111001", "1", "0"], m = 5, n = 3
输出:4
解释:最多有 5 个 0 和 3 个 1 的最大子集是 {"10","0001","1","0"} ,因此答案是 4 。
其他满足题意但较小的子集包括 {"0001","1"} 和 {"10","1","0"} 。{"111001"} 不满足题意,因为它含 4 个 1 ,大于 n 的值 3 。

示例 2:

输入:strs = ["10", "0", "1"], m = 1, n = 1
输出:2
解释:最大的子集是 {"0", "1"} ,所以答案是 2 。

提示:

  • 1 <= strs.length <= 600
  • 1 <= strs[i].length <= 100
  • strs[i] 仅由 '0''1' 组成
  • 1 <= m, n <= 100

思路

问题转化为二维费用的01背包问题:

  1. 状态表示:
    • dp[i][j][k] 表示从前 i 个字符串中挑选,字符 0 的个数不超过 j,字符 1 的个数不超过 k,所有的选法中,最大的长度。
  2. 状态转移方程:
    • 根据最后一步的状况,分两种情况讨论:
      • 不选第 i 个字符串:相当于去前 i - 1 个字符串中挑选,并且字符 0 的个数不超过 j,字符 1 的个数不超过 k。此时的最大长度为 dp[i][j][k] = dp[i - 1][j][k]
      • 选择第 i 个字符串:接下来在前 i - 1 个字符串中挑选,字符 0 的个数不超过 j - a,字符 1 的个数不超过 k - b 的最大长度,然后在这个长度后面加上字符串 i。此时 dp[i][j][k] = dp[i - 1][j - a][k - b] + 1。需要特判这种状态是否存在。
    • 综上,状态转移方程为:dp[i][j][k] = max(dp[i][j][k], dp[i - 1][j - a][k - b] + 1)
  3. 初始化:
    • 当没有字符串的时候,没有长度,因此初始化为 0
  4. 填表顺序:
    • 保证第一维的循环从小到大即可。
  5. 返回值:
    • 根据状态表示,返回 dp[l][m][n]

代码

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        int l=strs.size();
        vector<vector<vector<int>>> dp(l+1,vector<vector<int>>(m+1,vector<int>(n+1)));
        for(int i=1;i<=l;i++){
            int a=0,b=0;
            for(char ch:strs[i-1])
                if(ch=='0') a++;
                else b++;
            for(int j=m;j>=0;j--)
                for(int k=n;k>=0;k--){
                    dp[i][j][k]=dp[i-1][j][k];
                    if(j>=a&&k>=b) dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-a][k-b]+1);
                }
        }
        return dp[l][m][n];
    }
};

02.盈利计划

题目链接:https://leetcode.cn/problems/profitable-schemes/

集团里有 n 名员工,他们可以完成各种各样的工作创造利润。

i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与。如果成员参与了其中一项工作,就不能参与另一项工作。

工作的任何至少产生 minProfit 利润的子集称为 盈利计划 。并且工作的成员总数最多为 n

有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7 的值

示例 1:

输入:n = 5, minProfit = 3, group = [2,2], profit = [2,3]
输出:2
解释:至少产生 3 的利润,该集团可以完成工作 0 和工作 1 ,或仅完成工作 1 。
总的来说,有两种计划。

示例 2:

输入:n = 10, minProfit = 5, group = [2,3,5], profit = [6,7,8]
输出:7
解释:至少产生 5 的利润,只要完成其中一种工作就行,所以该集团可以完成任何工作。
有 7 种可能的计划:(0),(1),(2),(0,1),(0,2),(1,2),以及 (0,1,2) 。

提示:

  • 1 <= n <= 100
  • 0 <= minProfit <= 100
  • 1 <= group.length <= 100
  • 1 <= group[i] <= 100
  • profit.length == group.length
  • 0 <= profit[i] <= 100

思路

  1. 状态表示:
    • dp[i][j][k] 表示从前 i 个计划中挑选,总人数不超过 j,总利润至少为 k,有多少种选法。
  2. 状态转移方程:
    • 根据最后一位的元素,有两种选择策略:
      • 不选第 i 位置的计划:此时只能在前 i - 1 个计划中挑选,总人数不超过 j,总利润至少为 k。此时有 dp[i - 1][j][k] 种选法。
      • 选择第 i 位置的计划:在前 i - 1 个计划中挑选的限制变成了,总人数不超过 j - g[i],总利润至少为 max(0, k - p[i])。此时有 dp[i - 1][j - g[i]][max(0, k - p[i])] 种选法。
    • 注意特殊情况:
      • 如果 j - g[i] < 0,说明人数过多,状态不合法,舍去。
      • 对于 k - p[i] < 0,说明利润太高,但问题要求至少为 k,因此将其取 max(0, k - p[i])
    • 综上,状态转移方程为:dp[i][j][k] = dp[i - 1][j][k] + dp[i - 1][j - g[i]][max(0, k - p[i])]
  3. 初始化:
    • 当没有任务时,利润为 0。在这种情况下,无论人数限制为多少,都能找到一个「空集」的方案。因此初始化 dp[0][j][0]1,其中 0 <= j <= n
  4. 填表顺序:
    • 根据状态转移方程,保证 i 从小到大即可。
  5. 返回值:
    • 根据状态表示,返回 dp[l][m][n],其中 l 表示计划数组的长度。

代码

class Solution {
    const int MOD=1e9+7;
public:
    int profitableSchemes(int n, int m, vector<int>& group, vector<int>& profit) {
        int l = group.size();
        vector<vector<vector<int>>> dp(l+1,vector<vector<int>>(n+1,vector<int>(m+1)));
        for(int j=0;j<=n;j++) dp[0][j][0]=1;
        for(int i=1;i<=l;i++)
            for(int j=0;j<=n;j++)
                for(int k=0;k<=m;k++){
                    dp[i][j][k]=dp[i-1][j][k];
                    if(j>=group[i-1]) 
                        dp[i][j][k]+=dp[i-1][j-group[i-1]][max(0,k-profit[i-1])];
                    dp[i][j][k]%=MOD;
                }
        return dp[l][n][m];
    }   
};

似包非包

组合总和 Ⅳ

题目链接:https://leetcode.cn/problems/combination-sum-iv/

给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。

题目数据保证答案符合 32 位整数范围。

示例 1:

输入:nums = [1,2,3], target = 4
输出:7
解释:
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。

示例 2:

输入:nums = [9], target = 3
输出:0

提示:

  • 1 <= nums.length <= 200
  • 1 <= nums[i] <= 1000
  • nums 中的所有元素 互不相同
  • 1 <= target <= 1000

思路

注意这里题目意思容易混淆概念,其实这里是一个排列问题而并非组合问题,所以应该是普通的动态规划问题

  1. 状态表示:
    • dp[i] 表示总和为 i 时,一共有多少种排列方案。
  2. 状态转移方程:
    • 对于 dp[i],根据最后一个位置划分,选择数组中的任意一个数 nums[j],其中 0 <= j <= n - 1
    • nums[j] <= i 时,排列数等于先找到 i - nums[j] 的方案数,然后在每一个方案后面加上一个数字 nums[j]
    • 因为有很多个 j 符合情况,状态转移方程为:dp[i] += dp[i - nums[j]],其中 0 <= j <= n - 1
  3. 初始化:
    • 当和为 0 时,我们可以什么都不选,即「空集」一种方案,因此 dp[0] = 1
  4. 填表顺序:
    • 根据状态转移方程,从左往右填表。
  5. 返回值:
    • 根据状态表示,返回 dp[target] 的值。

代码

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<double> dp(target+1);
        dp[0]=1;
        for(int i=1;i<=target;i++)
            for(int& x:nums)
                if(x<=i) dp[i]+=dp[i-x];
        return dp[target];
    }
};

卡特兰数

不同的二叉搜索树

题目链接:https://leetcode.cn/problems/unique-binary-search-trees/

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

思路

  1. 状态表示:
    • dp[i] 表示当结点数量为 i 个时,一共有多少颗 BST。
  2. 状态转移方程:
    • 对于 dp[i],选择每一个结点 j 作为头结点,分析不同头结点的 BST 数量。
    • 根据 BST 的定义,j 号结点的左子树的结点编号在 [1, j-1] 之间,有 j-1 个结点,右子树的结点编号在 [j+1, i] 之间,有 i-j 个结点。
    • 因此,j 号结点作为头结点的 BST 种类数量为 dp[j-1] * dp[i-j]
    • 综合每一个可能的头结点,状态转移方程为:dp[i] += dp[j-1] * dp[i-j],其中 1 <= j <= i
  3. 初始化:
    • dp[0] 表示空树,也是一颗二叉搜索树,因此 dp[0] = 1
    • 针对 i 从 1 开始的情况,需要通过 dp[j-1] * dp[i-j] 来计算。
  4. 填表顺序:
    • 从左往右填表,保证每一步都有所依赖的子问题的解。
  5. 返回值:
    • 返回 dp[n] 的值,表示结点数量为 n 时的 BST 种类数量。

代码

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n+1);
        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];
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/433348.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot自动装配的原理

Springboot自动装配 1.前言2.EnableAutoConfiguration3.AutoConfigurationImportSelector4.spring.factories5.总结 1.前言 为什么springboot能够开箱即用&#xff0c;就是由于Springboot的自动装配。我们知道项目启动的方法上面都有一个注解SpringBootApplication&#xff0c…

武汉灰京文化:游戏市场推广与用户增长的成功典范

作为游戏行业的明星企业&#xff0c;武汉灰京文化在市场推广和用户增长方面的成功经验备受瞩目。他们以创造性和独特性的市场营销策略&#xff0c;成功吸引了大量用户。这不仅提高了其游戏的知名度&#xff0c;还为公司带来了持续的增长。这一成功模式不仅对公司自身有益&#…

计算机中msvcp140.dll,丢失怎么修复与解决

一、msvcp140.dll20个软件环境 msvcp140.dll文件是许多软件运行环境的组成部分&#xff0c;通常与Microsoft Visual C Redistributable关联。以下是可能使用该文件的软件环境&#xff1a; 微软办公软件&#xff1a;如Microsoft Office套件&#xff0c;包括Word、Excel、Power…

仓库福音!三防工业手机:远程RFID和条形码扫描仪的优势

在仓库中&#xff0c;由于堆货量众多&#xff0c;仓库管理员想要细分货物的种类十分困难&#xff0c;因此保持准确的库存记录至关重要&#xff0c;这样公司就不会导致货物积压。资产跟踪也可能是繁琐的任务之一&#xff0c;会对公司产生重大影响。没有为特定部件记录准确或错误…

[Echart]图谱中的富文本标签

[Echart]图谱中的富文本标签 series-graph.links.label.rich option {title: {text: Basic Graph},tooltip: {},animationDurationUpdate: 1500,animationEasingUpdate: quinticInOut,series: [{type: graph,// layout: force,symbolSize: 50,roam: true,label: {show: tru…

C及C++每日练习(2)

1.选择&#xff1a; 1.使用printf函数打印一个double类型的数据&#xff0c;要求&#xff1a;输出为10进制&#xff0c;输出左对齐30个字符&#xff0c;4位精度。以下哪个选项是正确的&#xff1f; A.%-30.4e B.%4.30e C.%-30.4f D.%-4.30 在上一篇文章中&#xff0c;提到了…

社科院与杜兰大学金融管理硕士——精心准备,只为那一刻的刚刚好

我们每个人都是夜空中独一无二的那颗星&#xff0c;静静地照耀&#xff0c;期待着照亮自己的宇宙。我们的每一步前行&#xff0c;都像是星尘累积&#xff0c;汇聚成璀璨的光轨&#xff0c;照亮未来的道路。正如我们现在努力申请的社科院与杜兰大学金融管理硕士项目&#xff0c;…

深圳/广州/厦门/上海/宁波/义乌2024最新跨境电商展计划表发布!

全国各城市2024年跨境电商年度效果好的跨境展会排期表来了&#xff0c;具体展会活动议程根据组委会实际公示结果为准。 励佳展览(上海)有限公司是一家专业组织、代理国内跨境电商行业展会会展公司&#xff0c;励佳展览拥有高素质的员工队伍&#xff0c;广泛的客户资源&#xf…

香港媒体发稿:【超值1元港媒发稿套餐】推广技巧-华媒舍

在当今竞争激烈的市场中&#xff0c;品牌的推广是企业取得成功的关键。众多的宣传渠道中&#xff0c;香港媒体发稿无疑是一种高效的品牌推广方式。本文将为您介绍《超值1元港媒发稿套餐》的各个组成部分&#xff0c;以及它如何帮助您实现品牌的腾飞。 1. 1元套餐的优势 1元港媒…

田宏斌:以人为本的听力健康管理实践经验 | 演讲嘉宾公布

一、助辅听器材Ⅲ分论坛 助辅听器材Ⅲ分论坛将于3月28日同期举办&#xff01; 听力贯穿人的一生&#xff0c;听觉在生命的各个阶段都是至关重要的功能&#xff0c;听力问题一旦出现&#xff0c;会严重影响生活质量。助辅听器材能有效提高生活品质。在这里&#xff0c;我们将分享…

逆变器专题(15)-弱电网下的LCL逆变器控制以及谐振峰问题(2)

相应仿真原件请移步资源下载 LCL滤波器 LCL滤波器因其本身为一个二阶系统&#xff0c;其本身就会引发谐振&#xff0c;导致相应谐振频率处的增益得到放大&#xff0c;进而产生谐波等问题&#xff1b;另一方面&#xff0c;在弱电网下&#xff0c;逆变器会与电网阻抗发生耦合&am…

IP劫持的危害及应对策略

随着互联网的发展&#xff0c;网络安全问题日益凸显&#xff0c;其中IP劫持作为一种常见的网络攻击手段&#xff0c;对个人和企业的信息安全造成了严重的威胁。IP数据云将分析IP劫持的危害&#xff0c;并提出相应的应对策略。 IP地址查询&#xff1a;IP数据云 - 免费IP地址查询…

多张gif怎么拼接?三步教你在线拼接gif

GIF拼图常用于制作表情包、动态海报、广告宣传等场景。它可以将多个图像或动画元素组合在一起&#xff0c;形成一个有趣、生动的动画效果&#xff0c;吸引观众的注意力&#xff0c;并传达特定的信息或情感。要将多个GIF动图拼接在一张图像上&#xff0c;要使用适合的gif动画图片…

奥壹科技推出婚恋相亲系统免费软件,旨在扶持创业者降低行业入门门槛

(广州, 2024年3月6日星期三) - 随着婚恋市场的日益增长&#xff0c;奥壹科技宣布推出其旗下奥壹云相亲系统的全新免费版(OEyun Free V1.0)。该公司表示&#xff0c;该举措旨在通过降低创业门槛&#xff0c;为有意进入婚恋行业的创业者及小型企业提供支持&#xff0c;从而进一步…

Java继承与多态:深入理解继承、组合和多态的精髓!

Java继承与多态&#xff1a;深入理解继承、组合和多态的精髓&#xff01; 引言 欢迎来到这篇关于Java继承与多态的博客&#xff01;在Java编程中&#xff0c;继承与多态是两个非常重要的概念&#xff0c;它们为我们构建灵活而高效的代码提供了强大的支持。本文将深入探讨Java继…

2024年冲刺年薪40w,Android岗面试

一个程序员&#xff0c;如果不想35 岁被淘汰&#xff0c;请把它当成一种信仰&#xff01; 25岁&#xff0c;一个北漂程序员&#xff0c;入职三年&#xff0c;Android中级工程师&#xff0c;月薪15k&#xff0c;965的工作经常干成996&#xff0c;比起老家的同龄人&#xff0c;我…

校招中的“熟悉linux操作系统”一般是指达到什么程度?

校招中的“熟悉linux操作系统”一般是指达到什么程度&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&am…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:PanGesture)

拖动手势事件&#xff0c;当滑动的最小距离超过设定的最小值时触发拖动手势事件。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 接口 PanGesture(value?: { fingers?: number; direction?: PanDir…

three.js如何实现简易3D机房?(二)模型加载的过渡动画

接上一篇&#xff1a; three.js如何实现简易3D机房&#xff1f;&#xff08;一&#xff09;基础准备-下&#xff1a;http://t.csdnimg.cn/TTI1P 目录 六、自定义过渡动画 1.过渡动画组件 2.模型加载时使用 根据模型大小&#xff0c;可以自定义模型加载的过渡动画效果&am…

修改表中某个字段等于另一个字段减去 2 小时的 SQL

需求&#xff1a;将表中到达时间按照客户要求改为比赛时间的提前 N 小时&#xff0c;具体如下&#xff1a; 表结构 update contestSchedule SET mainRefereeArrivalTimeDATE_FORMAT(CONCAT(2024-03-04 ,gameTime)- INTERVAL 2 HOUR, %H:%i), assistantRefereeArrivalTimeDAT…
最新文章