当前位置: 首页 > news >正文

每日算法刷题Day84:11.11:leetcode 动态规划9道题,用时2h

一、爬楼梯

1.套路

1.本质是爬楼梯问题:每次可以爬多种高度的楼梯,相互独立,最终从0层爬到target层,求不同方案个数(调换一个方案中的两次楼梯就视作另一种方案)
2.代码:

typedef long long ll;
vector<ll> f; // 从0爬到i的不同方案个数
// 假设vector<int> nums记录可以爬的高度
f[0]=1; // 赋初值
for(int i=1;i<=target;++i){ // 递推for(int& x:nums){// 从i-x爬x到iif(i-x>=0) f[i]+=f[i-x];}
}
return f[target]; // 最终答案
2.题目描述
3.学习经验
1. 70.爬楼梯(简单,学习)

70. 爬楼梯 - 力扣(LeetCode)

思想

1.假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
2.启发思考:寻找子问题
题目要求从0爬到n的方法数量(原问题),而n可以由n-1或n-2爬到,所以转化为求从0爬到n-2(子问题1)和从0爬到n-1(子问题2)的方法数量,这两种情况都把原问题转化为规模更小的子问题,所以可以用递归解决
:从大往小思考,主要是为了方便把递归翻译成递推。
3.递归写法:
(1)状态定义:dfs(i)表示从0爬到i的方法数量
(2)转态转移方程:由2分析可知,dfs(i)=dfs(i-1)+dfs(i-2)(递归得到)
(3)状态初值(递归终止条件):dfs(0)=dfs(1)=1(因为dfs(2)=dfs(0)+dfs(1)=2,所以逆向推出dfs(0)=1)
4.递归+记录返回值=记忆化搜索
对于3,dfs(i-2)会被dfs(i)和dfs(i-1)都调用,产生重叠子问题,所以拿一个数组记录dfs(i),若没调用过(数组值为初值),则调用并更新数组,否则在调用前返回数组值
5.1:1翻译成递推
把3/4的递归的递去掉,只保留归,则从自顶向下变成自底向上,状态定义和状态转移方程一致,但从递归终止条件(转态初值)向上归,f[i]=f[i-1]+f[i-2],答案为f[n](递归入口,归结束)
6.空间优化
根据f[i]=f[i-1]+f[i-2]得知,得到f[i]后,f[i-2]及其之前值不会再用,所以只要知道前一个值和前前一个值就能得到当前值(需判断开始情况),辗转更新

代码

3.递归写法:

class Solution {
public:int dfs(int n) {if (n <= 1)return 1;return dfs(n - 1) + dfs(n - 2);}int climbStairs(int n) { return dfs(n); }
};

4.递归+记录返回值=记忆化搜索

class Solution {
public:vector<int> memory;int dfs(int n) {if (n <= 1)return 1;if (memory[n] != -1)return memory[n];return memory[n] = dfs(n - 1) + dfs(n - 2);}int climbStairs(int n) {memory.resize(n + 1, -1); //[0,n]return dfs(n);}
};

5.1:1翻译成递推

class Solution {
public:vector<int> f;int climbStairs(int n) {f.resize(n + 1); //[0,n]f[0] = f[1] = 1;for (int i = 2; i <= n; ++i) {f[i] = f[i - 1] + f[i - 2];}return f[n];}
};

6.空间优化

class Solution {
public:int climbStairs(int n) {if(n<=1)    return 1;int preVal = 1, prePreVal = 1, newVal;for (int i = 2; i <= n; ++i) {newVal = preVal + prePreVal;prePreVal = preVal;preVal = newVal;}return newVal;}
};
2. 746. 使用最小花费爬楼梯(简单)

746. 使用最小花费爬楼梯 - 力扣(LeetCode)

思想

1.给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。
你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。
请你计算并返回达到楼梯顶部的最低花费。
2.f[i]表示从0爬到i的最低花费

代码
class Solution {
public:// f[i]:从0爬到i的最小花费int n;int minCostClimbingStairs(vector<int>& cost) {n = cost.size();if (n == 1)return cost[0];if (n == 2)return min(cost[0], cost[1]);int prePreVal = cost[0], preVal = cost[1], newVal;for (int i = 2; i <= n; ++i) {newVal = min(preVal, prePreVal);if (i < n) // 向上爬newVal += cost[i];prePreVal = preVal;preVal = newVal;}return newVal;}
};
3. 3693.爬楼梯II(中等)

https://leetcode.cn/problems/climbing-stairs-ii/description/

思想

1.你正在爬一个有 n + 1 级台阶的楼梯,台阶编号从 0 到 n
你还得到了一个长度为 n 的 下标从 1 开始 的整数数组 costs,其中 costs[i] 是第 i 级台阶的成本。
从第 i 级台阶,你 只能 跳到第 i + 1i + 2 或 i + 3 级台阶。从第 i 级台阶跳到第 j 级台阶的成本定义为: costs[j] + (j - i)2
你从第 0 级台阶开始,初始 cost = 0
返回到达第 n 级台阶所需的 最小 总成本。
3.f[i]表示从0爬到i的最小总成本

代码
class Solution {
public:vector<int> f;int n;int climbStairs(int n, vector<int>& costs) {n = costs.size();f.resize(n + 1);f[0] = 0;f[1] = costs[1 - 1] + 1;if (n == 1)return f[1];f[2] = costs[2 - 1] + min(f[0] + 4, f[1] + 1);for (int i = 3; i <= n; ++i) {f[i] = min({f[i - 3] + 9, f[i - 2] + 4, f[i - 1] + 1});f[i] += costs[i - 1];}return f[n];}
};
4. 377.组合总和IV(中等,学习)

https://leetcode.cn/problems/combination-sum-iv/description/

思想

1.给你一个由 不同 整数组成的数组 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.此题本质是[[十八.动态规划-一.入门DP#1. 70.爬楼梯(简单,学习)]],只不过现在可以爬nums中的任意值,即题意是从0级开始,从nums中任意爬任意次各台阶,最终到达target的不同方案个数

代码
class Solution {
public:typedef unsigned long long ull;vector<ull> f;int combinationSum4(vector<int>& nums, int target) {sort(nums.begin(), nums.end());f.resize(target + 1);f[0] = 1;for (int i = 1; i <= target; ++i) {for (int& x : nums) {if (i - x >= 0)f[i] += f[i - x];elsebreak;}}return f[target];}
};
5. 2466.统计构造好字符串的方案数(中等)

2466. 统计构造好字符串的方案数 - 力扣(LeetCode)

思想

1.给你整数 zero ,one ,low 和 high ,我们从空字符串开始构造一个字符串,每一步执行下面操作中的一种:

  • 将 '0' 在字符串末尾添加 zero  次。
  • 将 '1' 在字符串末尾添加 one 次。
    以上操作可以执行任意次。
    如果通过以上过程得到一个 长度 在 low 和 high 之间(包含上下边界)的字符串,那么这个字符串我们称为  字符串。
    请你返回满足以上要求的 不同 好字符串数目。由于答案可能很大,请将结果对 109 + 7 取余 后返回。
    2.还是爬楼梯,这次一次·可以爬zeroone层,最终到达[low,high]之间
代码
class Solution {
public:typedef long long ll;vector<ll> f; // 从0到长度i的字符串个数const int mod = 1e9 + 7;int countGoodStrings(int low, int high, int zero, int one) {f.resize(high + 1);f[0] = 1;for (int i = 1; i <= high; ++i) {// i-zero,i-oneif (i - zero >= 0)f[i] = (f[i] + f[i - zero]) % mod;if (i - one >= 0)f[i] = (f[i] + f[i - one]) % mod;}int res = 0;for (int i = low; i <= high; ++i) {res = (res + f[i]) % mod;}return res;}
};

二、打家劫舍

1.套路

1.相邻数字不能同时选想到打家劫舍问题,转换成相邻项([[十八.动态规划-一.入门DP#2. 213.打家劫舍II(中等,学习)]]对第0家分类讨论转变为原始打家劫舍,[[十八.动态规划-一.入门DP#4. 740.删除并获得点数(中等,学习)]]转化为值域数组转变为原始打家劫舍)

2.题目描述
3.学习经验
1. 198.打家劫舍(中等)

198. 打家劫舍 - 力扣(LeetCode)

思想

1.你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
2.子问题:f[i]表示偷i家的最高金额

代码
class Solution {
public:typedef long long ll;vector<ll> f; // f[i]:从i家能偷到的最高金额int n;int rob(vector<int>& nums) {n = nums.size();f.resize(n + 1);f[0] = 0;f[1] = nums[0];if (n == 1)return f[1];f[2] = max(f[1], 1LL * nums[1]);for (int i = 2; i <= n; ++i) {// 偷i:nums[i-1]+f[i-2],不偷i:f[i-1]f[i] = max(f[i - 1], nums[i - 1] + f[i - 2]);}return f[n];}
};
2. 213.打家劫舍II(中等,学习)

213. 打家劫舍 II - 力扣(LeetCode)

思想

1.你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。
2.此题限制是第0家和第n-1家不能同时选,所以以选不选第0家进行分类讨论

  • 选第0家,那么1和n-1不能选,可选范围[2,n-2]
  • 不选第0家,可选范围[1,n-1]
    可选范围的选择变成[[十八.动态规划-一.入门DP#1. 198.打家劫舍(中等)]]题
代码
class Solution {
public:int rob1(vector<int>& nums, int left, int right) {// nums:[left,right]int len = right - left + 1; // 共len家vector<int> f(len + 1);     // f[i]:偷i家f[0] = 0;f[1] = nums[left];if (len == 1)return f[1];f[2] = max(nums[left], nums[left + 1]);for (int i = 2; i <= len; ++i) {f[i] = max(f[i - 2] + nums[left + i - 1], f[i - 1]);}return f[len];}int n;int rob(vector<int>& nums) {n = nums.size();if (n == 1)return nums[0];if (n == 2)return max(nums[0], nums[1]);if (n == 3)return max({nums[0], nums[1], nums[2]});// 选nums[0],不能选nums[1]和nums[n-1],范围[2,n-2],不选nums[0],范围[1,n-1],要求n>=4return max(nums[0] + rob1(nums, 2, n - 2), rob1(nums, 1, n - 1));}
};
3. 2320.统计放置房子的方式数(中等)

2320. 统计放置房子的方式数 - 力扣(LeetCode)

思想

1.一条街道上共有 n * 2 个 地块 ,街道的两侧各有 n 个地块。每一边的地块都按从 1 到 n 编号。每个地块上都可以放置一所房子。
现要求街道同一侧不能存在两所房子相邻的情况,请你计算并返回放置房屋的方式数目。由于答案可能很大,需要对 109 + 7 取余后再返回。
注意,如果一所房子放置在这条街某一侧上的第 i 个地块,不影响在另一侧的第 i 个地块放置房子。

代码
class Solution {
public:typedef long long ll;vector<ll> f; // f[i]:i块地块放置房屋方案数const int mod = 1e9 + 7;int countHousePlacements(int n) {f.resize(n + 1);f[0] = 1; // 不放也是1种方案f[1] = 2;if (n == 1)return f[1] * f[1];// 第i块放:f[i-2],不放:f[i-1]for (int i = 2; i <= n; ++i) {f[i] = (f[i - 2] + f[i - 1]) % mod;}return f[n] * f[n] % mod;}
};
4. 740.删除并获得点数(中等,学习)

740. 删除并获得点数 - 力扣(LeetCode)

思想

1.给你一个整数数组 nums ,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
2.相邻数字不能同时选,打家劫舍问题。
但此题同一个值的数字为一个范围,所以转换成值域数组:sum[i]表示nums种值为i的元素之和,然后对值域数组使用打家劫舍问题动态规划算法

代码
class Solution {
public:typedef long long ll;int n;vector<ll> sum, f; // sum[x]:值为x的和, f[i]表示共i个数int deleteAndEarn(vector<int>& nums) {n = nums.size();int maxn = INT_MIN;for (int& x : nums)maxn = max(maxn, x);sum.resize(maxn + 1);f.resize(maxn + 2); // 共maxn+1个数,[0,maxn+1]for (int& x : nums)sum[x] += x;f[0] = 0;f[1] = sum[0];if (maxn == 0)return f[1];for (int i = 2; i <= maxn + 1; ++i) {f[i] = max(f[i - 2] + sum[i - 1], f[i - 1]);}return f[maxn + 1];}
};
http://www.dtcms.com/a/598576.html

相关文章:

  • 网站建设开发设计营销公司山东建设网站平台合同范本
  • 网站建设玖金手指谷哥四网站对一个关键词做排名怎么做
  • Windows 系统上安装 Kafka
  • 不成立公司怎么做企业网站php网站开发占比
  • 机加工如何用网站开发客户php实现网站消息推送
  • 百日挑战——单词篇(第十九天)
  • RabbitMQ 小项目之扫盲班
  • 自己如何在网上做网站黄页88网企业名录
  • 信宜做网站动漫制作专业就业方向
  • 国外网站会让国内人做吗ts431p 做网站
  • 酒店网站制作公司企业网站要怎么建设
  • 微信开发网站制作宣传片拍摄报价明细
  • 鹤山市住房和城乡建设局网站深圳做网页
  • LayUI基础入门
  • 56_AI智能体运维部署之实战指南:编写生产级docker-compose部署脚本
  • 公司制作一个网站价格全屋定制一般多少钱
  • 做网站为什么要租服务器广西来宾网站网站建设
  • 制作免费网站微信公众号开发流程图
  • K8S Base: CrashLoopBackOff
  • 《Python 小程序编写系列》(第三部):简易文件批量重命名工具
  • 建设信息门户网站的条件广州设计网站公司
  • 国内做网站的大公司有哪些歌手投票网站怎么做
  • 【系统分析师】2025年下半年真题:案例分析-答案及详解(回忆版)
  • 关系数据库小测练习笔记(1)
  • 门源县电子商务网站建设公司在线短网址生成工具
  • 河南商务学校网站建设污染网站代码
  • 毕业设计做一个网站怎么做网站模板双语
  • 阿里个人网站自动建站网站源码
  • c语言16:结构体对齐,从原理到大小计算
  • 模板免费网站wordpress手机底部导航