炫酷网站模板免费下载玉林做绿化苗木网站的是哪个单位
炫酷网站模板免费下载,玉林做绿化苗木网站的是哪个单位,wordpress怎么获取在线ip,wordpress 没有远程发布一.爬楼梯
leetcode 746.使用最小花费爬楼梯
#xff08;1#xff09;递归
思路#xff1a;
1.分析状态
题目要求从0爬到第n个台阶#xff0c;我们不妨想想到第i个台阶是什么样的#xff1f;
令f(i)是到第i个台阶的最小花费#xff0c;那么他该怎么表达呢#xff…一.爬楼梯leetcode 746.使用最小花费爬楼梯1递归思路1.分析状态题目要求从0爬到第n个台阶我们不妨想想到第i个台阶是什么样的令f(i)是到第i个台阶的最小花费那么他该怎么表达呢题目中说如果你支付台阶的费用那么你可以向上爬1或2个台阶我们不妨想一下递归的过程那么第i个台阶可以是第i-1个台阶上来的也可以是第i-2个台阶上来的那么就很明朗了两种情况取最小值即可.可以得出f(i) min(f(i - 1) cost[i - 1],f(i - 2) cost[i - 2]);这个式子。2.边界情况这里自顶向下递归当i 1的时候无台阶可爬(起点)返回0代码 class Solution { public: int minCostClimbingStairs(vectorint cost){ int n cost.size(); auto dp [](this auto dp,int i){ if(i 1){ return 0; } return min(dp(i - 1) cost[i - 1],dp(i - 2) cost[i - 2]); }; return dp(n); } }; 嗯在leetcode上写的时候运行能通过,可是提交的时候显示超出时间限制怎么办呢2递归优化-记忆化搜索注意调用f(i-1)的时候又会产生两个分支f(i-2),f(i-3),而f(i-2)之前在调用f(i)的时候计算过了......以此类推在递归的过程中会不断产生相同的分支。因此我们可以将这些分支全部剪掉。减少不必要的计算。具体做法创建一个数组memo并设置不会出bug的初始值以i当访问该数组的下标以f(i)作为memo[i]存的值在每次访问的时候发现f(i)的量不等于初始值的时候返回memo[i]的值即可。代码class Solution { public: int minCostClimbingStairs(vectorint cost) { int n cost.size(); vectorint memo(n 1,-1); auto dp [](this auto dp,int i){ if(i 1){ return 0; } int ret memo[i]; if(ret -1){ return ret; } return ret min(dp(i - 1) cost[i - 1],dp(i - 2) cost[i - 2]); }; return dp(n); } };int ret类似于c语言的指针是引用符赋值的时候不用像指针一样解引用也能存里面(3)转化成递推递推与递归本质是同一问题的两种表现形式递推从已知向未知逐步求解递归从未知向已知回溯。两者可通过状态定义与转移方程统一。递推从边界正向推导逐步填充状态。思路1.找式子只不过这次变成递推式有了递归的经验很容易便能找到递推式f[i]min(f[i−1]cost[i−1],f[i−2]cost[i−2])2.递推入口我们自底向上计算题目告诉我们可以从第01个台阶向上走因此f[0] 0;f[1] 0;3.返回值f[i]表示前i个的最小值那么f[n]表示前n-1个最小值返回f[n]代码class Solution { public: int minCostClimbingStairs(vectorint cost) { int n cost.size(); vectorint f(n 1); for (int i 2; i n; i) { f[i] min(f[i - 1] cost[i - 1], f[i - 2] cost[i - 2]); } return f[n]; } };看有多少种状态决定开多大的数组二丶打家劫舍问题leetcode 198. 打家劫舍1)递归自动记忆化了哈思路1.状态表示设f(i)是前i个能偷到的最大金额怎么来的假设前一次行动没偷那可以是从i-1来的如果是这样那这次就不能再偷了。假设前一次行动偷了那只能是i-2或者之前来的。又因为nums[i] 0那么我们尽可能偷就行了只考虑这两种情况。可以列出f(i) max(f(i - 1),f(i - 2)nums[i]);2.递归边界当i0的时候没房子能偷返回03.入口自顶向下算因此是从n - 1开始。代码class Solution { public: int rob(vectorint nums) { int n nums.size(); vectorint memo(n,-1); auto dp [](this auto dp,int i){ if(i 0){ return 0; } int ret memo[i]; if(ret -1){ return ret; } return ret max(dp(i - 2) nums[i],dp(i - 1)); }; return dp(n - 1); } };2递推思路1.式子从上一集不难看出来式子为f[i] max(f[i - 1],f[i - 2] nums[i]);2.入口不难发现递归最后遍历到的东西f(-1),f(-2)可这玩意在数组里指定越界怎么办数组整体往后移两位令f(0) 0,f(1) 0即可。3.大小从上分析不难得出大小是n 2(考虑俩越界的代码class Solution { public: int rob(vectorint nums) { int n nums.size(); vectorint f(n 2); for(int i 2; i n 2; i){ f[i] max(f[i - 1],f[i - 2] nums[i - 2]); } return f[n 1]; } };(nums里那个i还是那个i没跟着f扩大因此访问的时候要-2三丶最大子数组和leetcode 53. 最大子数组和(1)递归思路1.状态表示题目要求我们求出子数组的最大和我们设f(i)是第i个元素及其之前所构成的最大和的子数组那么f(i-1)就是第i-1及其之前元素所构成的最大和的子数组对于f(i-1),我们有选或不选两种情况而对于nums[i]我们必须选因为子数组不能为空。怎么思考选或者不选呢当f(i-1)小于0的时候不选因为选他比不选他还小当f(i-1) 0的时候就可以选了要么不变要么更大。由此我们可以列出式子f(i) max(f(i - 1),0) nums[i];2.递归边界当i 0的时候不可能存在子数组返回INT_MIN。3.入口自顶向下算。注意因为是子数组所以在哪里结尾都有可能我们得枚举从0到n-1所有可能的结尾也就是枚举入口。4.代码class Solution { public: int maxSubArray(vectorint nums) { int n nums.size(); vectorint memo(n 1,INT_MIN); auto dp [](this auto dp,int i){ if(i 0){ return INT_MIN; } int ret memo[i]; if(ret ! INT_MIN){ return ret; } return ret max(dp(i - 1),0) nums[i]; }; int ans INT_MIN; for(int i 0; i n; i) { ans max(ans, dp(i)); } return ans; } };这种用递归实现会麻烦一点2递推思路其实递归那里基本都想完了1.式子由上可得f[i] max(f[i - 1],0) nums[i];2.入口由于子数组不能为空所以入口是nums[i]。3.大小从n到0开大小为n的数组4.代码 class Solution { public: int maxSubArray(vectorint nums) { int n nums.size(); vectorint f(n); f[0] nums[0]; for (int i 1; i nums.size(); i) { f[i] max(f[i - 1], 0) nums[i]; } return ranges::max(f); } }; 由于数组会存下每一种结尾可能的最大值,所以我们只用往后推就行结果交给max函数总结定义状态明确dp(i)或f[i]的含义。写出转移方程分析状态之间的关系。确定边界与入口确保递推/递归有起点。选择实现方式递归记忆化或递推根据问题特点选择。避免模板化理解本质灵活应用