力扣刷题笔记——动态规划

 动态规划基础

 简称DP如果某⼀问题有很多重叠⼦问题,使⽤动态规划是最有效的。

 动态规划中每⼀个状态⼀定是由上⼀个状态推导出来的
1. 确定dp 数组( dp table )以及下标的含义
2. 确定递推公式
3. dp 数组如何初始化
4. 确定遍历顺序
5. 举例推导 dp 数组

509. 斐波那契数

509. 斐波那契数 - 力扣(LeetCode)https://leetcode.cn/problems/fibonacci-number/

 首先思考dp数组的含义:

dp[i]是指数组中第i个数的值

状态转移方程:dp[i]=dp[i-1]+dp[i-2]

初始化:初始第1和第2个数

确定遍历顺序从头开始到第n个

举例推导dp[i] = dp[i - 1] + dp[i - 2]
class Solution {
public:int fib(int N) {if (N <= 1) return N;vector<int> dp(N + 1);dp[0] = 0;dp[1] = 1;for (int i = 2; i <= N; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[N];
}
};

70.爬楼梯 

70. 爬楼梯 - 力扣(LeetCode)https://leetcode.cn/problems/climbing-stairs/

首先思考dp数组得含义:

dp[i]是指爬到第i阶有几种方法

dp[i]=dp[i-1] + dp[i-2]

初始化:初始第1和第2个数

确定遍历顺序从头开始到第n个

举例推导dp[i] = dp[i - 1] + dp[i - 2]
class Solution {
public:int climbStairs(int n) {if(n<=2){return n;   }vector<int> vec(n+1,0);vec[1]=1;vec[2]=2;for(int i=3;i<=n;i++){vec[i]=vec[i-1]+vec[i-2];}        return vec[n];}
};

746. 使用最小花费爬楼梯


746. 使用最小花费爬楼梯 - 力扣(LeetCode)https://leetcode.cn/problems/min-cost-climbing-stairs/submissions/

dp[i]表示到达第i个台阶最小的花费

dp[i]=min(dp[i-1],dp[i-2])+cost[i];

初始化dp[0]=cost[0] dp[1]=cost[1]

顺序是从第2个台阶开始 

class Solution {
public:int minCostClimbingStairs(vector<int>& cost) {vector<int> dp(cost.size(),0);    //初始化数组dp[0]=cost[0];dp[1]=cost[1];for(int i=2;i<cost.size();i++){dp[i]=min(dp[i-1],dp[i-2])+cost[i];}return min(dp[cost.size()-1],dp[cost.size()-2]);}
};

 62.不同路径

62. 不同路径 - 力扣(LeetCode)https://leetcode.cn/problems/unique-paths/

本题需要记录每个位置的可以到达的路径的数目

dp[i][j]表示到达第i行第j列的点的路径

dp[i][j]=dp[i-1][j]+dp[i][j-1] 每一个位置,可以通过上面和左边的位置前进一步得到

初始化明显dp[i][0]=1 dp[0][j]=1 表示第一行和第一列的到达的路径都为1

遍历的顺序从每层一层一层遍历

class Solution {
public:
int uniquePaths(int m, int n) {vector<vector<int>>  dp(m, vector<int>(n, 1));for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];
}
};

 63.不同的路径II

63. 不同路径 II - 力扣(LeetCode)https://leetcode.cn/problems/unique-paths-ii/

 本体相对于上一题,中间多了路障

在初始化地图时,我们需要将有障碍的地方识别出来

对于每一个点,都可以通过上面或者左边的节点过来

状态转移方程:grid[i][j]=grid[i-1][j]+grid[i][j-1]

初始化:第一行和第一列每一个元素初始化为1

顺序:每一行不停的向下遍历

最后返回grid[obstacledGrid.size()][obstacleGrid[0].size()]

class Solution {
public:int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {int n=obstacleGrid.size();int m=obstacleGrid[0].size();vector<vector<int>>  grid(n,vector<int>(m,0));//初始化数组 第一行和第一列可以到达的路径都是1for(int i=0;i<n&&obstacleGrid[i][0]==0;i++) grid[i][0]=1;for(int j=0;j<m&&obstacleGrid[0][j]==0;j++) grid[0][j]=1;for(int i=1;i<n;i++){for(int j=1;j<m;j++){if(obstacleGrid[i][j]==1) continue;grid[i][j]=grid[i-1][j]+grid[i][j-1];}}return grid[n-1][m-1];}
};

 343 整数拆分

343. 整数拆分 - 力扣(LeetCode)https://leetcode.cn/problems/integer-break/

dp[i]表示i拆分的最大的乘积

递推公式(状态转移公式):遍历之前的dp数据 dp[i]=max(dp[i],max(dp[i-j]*j,j*(i-j)));

dp[i]很小(起一个迭代的作用),因此取最大值基本都是后一个max中的值(dp[i-j]表示i-j拆分成的最大乘积,如果这个树乘以j大,那么不断循环,到i-1的情况,就可以找出i拆分的最大的值)

初始化,对于0和1没法拆分,那么最大的乘积为0

顺序:从1开始,从前往后

class Solution {
public:int integerBreak(int n) {vector<int> dp(n+1,0);dp[2]=1;for(int i=3;i<=n;i++){for(int j=1;j<i-1;j++){dp[i]=max(dp[i],max(dp[i-j]*j,j*(i-j)));}}return dp[n];}
};

96.不同的二叉搜索树 

96. 不同的二叉搜索树 - 力扣(LeetCode)https://leetcode.cn/problems/unique-binary-search-trees/

dp[n] 一维的数组,思考含义i表示i个元素可以构成的二叉搜索树的个数

状态转移:dp[i]+=dp[j-1][i-j] (j的范围为1到i)

初始化思考i为0的情况:0个元素构成的搜索树可以直接看成一个二叉搜索树dp[0]=1

顺序:从第一个节点开始,直到第n个节点

返回 dp[n];

 为什么是乘法呢,因为左右子树相当于不同的选择步骤

因此,最终的结果的个数应该是两者的乘积

class Solution {
public:int numTrees(int n) {//dp[i]为i个节点时,二叉搜索树的中枢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];}};

背包问题

背包问题是动态规划经典的问题,包含01背包,完全背包,多重背包等子问题

0-1背包问题

N 件物品和⼀个最多能被重量为 W 的背包。第 i 件物品的重量是 weight[i] ,得到的价值是
value[i] 每件物品只能⽤⼀次 ,求解将哪些物品装⼊背包⾥物品价值总和最⼤。
总结一下,就是把给定的物品向背包里装,求出能够装进去的最大价值

 定义一个数组int dp[i][j] ,i和物品的数量一样 j为背包的最大容量

dp[i][j] 为在容量为j的情况下,前i个物品合理装进去能够获得的最大的价值

转移公式: dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);

初始化:对于j取j<value[0]是为0,如果j>value[0],则为value[0];

int main(){vector<vector<int>> dp(weight.size()+1,vector<int>(rongliang+1,0));//全部初始化为0for(int j=value[0];j<=rongliang;j++){dp[0][j]=value[0];}for(int i=1;i<weight.size();i++){for(int j=0;j<=rongliang;j++){if(j<weight[i]) dp[i][j]=dp[i-1][j];elsedp[i][j] = max(dp[i - 1][j], dp[i - 1][j-weight[i]] + value[i]);    }}cout << dp[weight.size() - 1][bagWeight] << endl;
}
#include<iostream>
#include<vector>using namespace std;int main() {int sum, rongliang;cin >> sum >> rongliang;vector<int>  tiji(sum+1, 0);vector<int>  jiazhi(sum+1, 0);for (int i = 1; i <= sum; i++) {cin >> tiji[i] >> jiazhi[i];}//初始化dp数组vector<vector<int>> dp(sum + 1, vector<int>(rongliang + 1, 0));//进行动态规划for (int i = 1; i <= sum; i++) {for (int j = rongliang; j >= 0; j--) {//状态转移方程if (j >= tiji[i]) {//装得下dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - tiji[i]] + jiazhi[i]);}else {//装不下dp[i][j] = dp[i - 1][j];}}}cout << dp[sum][rongliang];return 0;
}

这两份代码不同:

第一:价值和重量数组的起始位置不同

第二:在第二轮循环中,第二个程序从大到小

起始位置不同,导致了初始化的过程不同,第二个不需要初始化,初始化化的过程包含在循环中

因为dp的值都是从上一行的状态转移过来的,那么就是说我们不要在意遍历的顺序,那么从开始到最后,从最后到开始都是一样的,我们依旧可以从容量开始,不断递减

思考如何简化问题的求解

使用一位动态数组就可以解决问题

dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);

如果说把dp[i-1]的那一层拷贝到i层,表达式就可以是dp[i][j]=max(dp[i][j],dp[i][j-weight[i]]+value[i]);

只是用一维数组,只使用dp[j]

416.分割等和子集

416. 分割等和子集 - 力扣(LeetCode)https://leetcode.cn/problems/partition-equal-subset-sum/

class Solution {
public:bool canPartition(vector<int>& nums) {int sum=0;vector<int> dp(10001,0);for(int i=0;i<nums.size();i++){sum+=nums[i];}if(sum%2!=0) return false;int target=sum/2;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(dp[target]==target) return true; return false;}
};

 分割子集,找到和相同的子集

分半,找到容量最大的;

dp数组含义,容量为i时,取得数组元素和的最大值

dp[i]=max(dp[i],dp[i-nums[i]]+nums[i])

初始化,当容量小于最小的数组元素时,dp为零,因此初始化为全零

1049. 最后一块石头的重量II

1049. 最后一块石头的重量 II - 力扣(LeetCode)https://leetcode.cn/problems/last-stone-weight-ii/

class Solution {
public:int lastStoneWeightII(vector<int>& stones) {int sum=0;for(int i=0;i<stones.size();i++){sum+=stones[i];}vector<int> vec(150001,0);int target=sum/2;for(int i=0;i<stones.size();i++){for(int j=target;j>=stones[i];j--){vec[j]=max(vec[j],vec[j-stones[i]]+stones[i]);}}return sum-vec[target]-vec[target];}
};

思考本题:
         总数分半,获得容量最大可能性

        sum-dp[target]-dp[target];

        sum-dp[target]一定大于dp[target] 

494、目标和 

494. 目标和 - 力扣(LeetCode)https://leetcode.cn/problems/target-sum/

在数字前面加+-号得到目标和的数

就是装够特定容量大小的东西,总共有几种装法

dp[j]+=dp[j-nums[i]] 

遍历的顺序和01背包问题一样

初始化:通过状态转移方程可以得出,当为0时,代表结果为0的时候有几种方案

class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int sum=0;for(auto i:nums){sum+=i;}if(target>sum) return 0;if((target+sum)%2==1) return 0;int nice=(target+sum)/2;vector<int> vec(1001,0);vec[0]=1;for(int i=0;i<nums.size();i++){for(int j=nice;j>=nums[i];j--){vec[j]+=vec[j-nums[i]];}}return vec[nice];}
};

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【Java系列】MyBatis-Plus常见面试题

问题列表 Q1&#xff1a;MyBatis-Plus是什么&#xff1f;它有什么优点&#xff1f; MyBatis-Plus是MyBatis框架的一个扩展库&#xff0c;它提供了一系列方便的API和工具&#xff0c;可以简化常见的数据库操作。MyBatis-Plus的优点包括&#xff1a; 提高开发效率&#xff1a;My…

MQTT与EMQ

文章目录 1 MQTT协议与EMQ中间件1.1 物联网消息协议MQTT1.1.1 什么是MQTT1.1.2 MQTT相关概念1.1.3 消息服务质量QoS——信息的可靠投递1.1.3.1 QoS0——消息服务质量为0&#xff0c;消息发送至多一次1.1.3.2 QoS1——消息发送至少一次1.1.3.3 QoS2——消息发送仅一次1.1.3.4 不…

MTK平台的SWT异常的简单总结(2)——SWT原理和分析

&#xff08;1&#xff09;原理性 &#xff08;2&#xff09;SWT如何抓取Log 遇到SWT问题详细可参考MTK提供的FAQ&#xff1a;SWT机制介绍。 获取Ap Log的路径&#xff1a;/sdcard/debuglogger/mobilelog/APLog_XXXXX 获取db的路径&#xff1a;/data/aee_exp 如果db没有打包…

HBase统计表行数(RowCount)的四种方法

背景&#xff1a; 对于其他数据存储系统来说&#xff0c;统计表的行数是再基本不过的操作了&#xff0c;一般实现都非常简单&#xff1b;但对于HBase这种key-value存储结构的列式数据库&#xff0c;统计 RowCount 的方法却有好几种不同的花样&#xff0c;并且执行效率差别巨大&…

2023年测试人前景归途?我主攻自动化测试拿到了25k的offer...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

sqlserver 中 @@rowcount的简单用法

返回受上一语句影响的行数。如果行数大于 20 亿&#xff0c;请使用 ROWCOUNT_BIG。 语法 ROWCOUNT 返回类型 int 注释 Transact-SQL 语句可以通过下列方式设置 ROWCOUNT 的值&#xff1a; 将 ROWCOUNT 设置为 受影响或被读取的行的数目。可以将行发送到客户端&#xff0c;…

SQL中row_number函数用法

row_number函数用法 1、函数讲解2、LeetCode实战 1、函数讲解 语法&#xff1a;ROW_NUMBER() OVER(PARTITION BY COLUMN ORDER BY COLUMN)简单的说&#xff0c;row_number()从1开始&#xff0c;为每条分组记录返回一个数字&#xff0c;举例&#xff1a; ROW_NUMBER() OVER(OR…

Hbase进行RowCount统计

对于Table内RowKey个数的统计&#xff0c;一直是HBase系统面临的一项重要工作&#xff0c;目前有三种执行该操作的方式。 测试环境&#xff1a; Apache版的 hadoop-2.6.0 &#xff08;cdh版的hadoop-2.6.0-cdh5.5.2也可以&#xff09; Apache版的 hbase-1.0.0 &#xff08;一…

【完整版】2023二级建造师《建筑实务》真题答案解析(2天考3科)

2023二级建造师考试将在6月3日、4日举行&#xff0c;2023二建《市政实务》考试时间&#xff08;2天考3科&#xff09;&#xff1a;6月4日 9:00-12:00&#xff0c; 考后甘建二将及时发布2023年二建市政实务真题及答案解析&#xff0c;敬请关注 2天考3科地区&#xff1a;四川、山…

DMBOK知识梳理for CDGA/CDGP——第三章数据治理

关 注gzh“大数据食铁兽” 回复“知识点”获取《DMBOK知识梳理for CDGA/CDGP》常考知识点&#xff08;第三章数据治理&#xff09; 第三章 数据治理 第三章在是CDGA|CDGP考试的重点考核章节之一&#xff0c;知识点比较密集&#xff0c;本章重点为语境关系图及数据治理概念…

LiangGaRy-学习笔记-Day19

1、回顾知识 1.1、文件系统说明 xfs与ext4文件系统 CentOS7以上&#xff1a;默认的就是XFS文件系统 xfs 使用的就是restore、dump等工具 CentOS6默认的就是ext4文件系统 extundelete工具就是用于ext4系统 1.2、回顾Linux文件系统 Linux文件系统是由三个部分组成 inode文…

一文学会MySQL四种安装方式

目录 &#x1f341;rpm方式安装 &#x1f340;下载软件包 &#x1f340;前置配置 &#x1f340;安装MySQL &#x1f341;yum方式安装 &#x1f340;下载软件包 &#x1f340;安装MySQL &#x1f341;二进制方式安装 &#x1f340;下载软件包 &#x1f340;安装MySQL &#x1f3…

2023最新网络安全面试题大全,看完这篇你的秋招offer就到手了!

前言 随着国家政策的扶持&#xff0c;网络安全行业也越来越为大众所熟知&#xff0c;想要进入到网络安全行业的人也越来越多。 为了拿到心仪的 Offer 之外&#xff0c;除了学好网络安全知识以外&#xff0c;还要应对好企业的面试。 作为一个安全老鸟&#xff0c;工作这么多年…

【自定义CPU占用率】

题目&#xff1a;写一个程序&#xff0c;让用户来决定Windows任务管理器&#xff08;Task Manager&#xff09;的CPU占用率。程序越精简越好&#xff0c;计算机语言不限。例如&#xff0c;可以实现下面三种情况&#xff1a; 1. CPU的占用率固定在50%&#xff0c;为一条直线&…

控制cpu占有率

http://www.cnblogs.com/Ripper-Y/archive/2012/05/19/2508511.html CPU正弦曲线 1 #include <iostream>2 #include <cmath>3 #include <ctime>4 #include <windows.h>5 6 using namespace std;7 8 //得到循环0xFFFFFFFF次用的秒数9 unsigned int te…

CPU正弦曲线

CPU正弦曲线 1 #include <iostream>2 #include <cmath>3 #include <ctime>4 #include <windows.h>5 6 using namespace std;7 8 //得到循环0xFFFFFFFF次用的秒数9 unsigned int test() 10 { 11 unsigned int c 0xFFFFFFFF; 12 13 time_t t1…

(1.5.1.1)编程之美:让CPU占用率曲线听你指挥

题目&#xff1a;写一个程序&#xff0c;让用户来决定Windows任务管理器&#xff08;Task Manager&#xff09;的CPU占用率。程序越精简越好&#xff0c;计算机语言不限。例如&#xff0c;可以实现下面三种情况&#xff1a; 1. CPU的占用率固定在50%&#xff0c;为一条直线&…

让CPU占用率曲线听你指挥

由于网上已经有很多有关此问题的博客&#xff0c;本文参考了http://blog.csdn.net/wesweeky/article/details/6402564 题目&#xff1a;写一个程序&#xff0c;让用户来决定Windows任务管理器&#xff08;Task Manager&#xff09;的CPU占用率。程序越精简越好&#xff0c;计…

现代计算机理论基础是什么_为什么旧游戏在现代计算机上运行得太快?

现代计算机理论基础是什么 If you’ve ever tried to get a vintage computer game up and running on a modern system, you’ve likely been shocked at how fast the game ran. Why do old games run out of control on modern hardware? 如果您曾经尝试过在现代系统上启动…

《编程之美》读书笔记23: 1.1 让CPU占用率曲线听你指挥

题目&#xff1a;写一个程序&#xff0c;让用户来决定Windows任务管理器&#xff08;Task Manager&#xff09;的CPU占用率。程序越精简越好&#xff0c;计算机语言不限。例如&#xff0c;可以实现下面三种情况&#xff1a; 1. CPU的占用率固定在50%&#xff0c;为一条直线&…