剑指offer第2版:动态规划+记忆化搜索

剑指offer第2版:动态规划+记忆化搜索

前三题是同一种模型,所以我分别用递推、记忆化、动归来做

一、p74-JZ10 斐波那契数列

斐波那契数列_牛客题霸_牛客网

class Solution { public: int Fibonacci(int n) { // write code here if(n==1||n==2) return 1; int a=1,b=1,c=1; while(n>2){ c=a+b; a=b; b=c; --n; } return c; } };

二、扩展p77-JZ10青蛙跳台阶

跳台阶_牛客题霸_牛客网

class Solution { public: //这题就用记忆化搜索 int memory[41]={0}; int jumpFloor(int n) { if(n<=2) return n;//考虑了1和2的情况 //此时至少是n==3 if(memory[n]) return memory[n]; return memory[n]=jumpFloor(n-1)+jumpFloor(n-2); } };

三、扩展p79-JZ10矩阵覆盖

矩形覆盖_牛客题霸_牛客网

class Solution { public: int rectCover(int n) { if(n<=2) return n; vector<int> dp(n+1); dp[1]=1,dp[2]=2; for(int i=3;i<=n;++i) dp[i]=dp[i-1]+dp[i-2];//最后放竖的或者放俩正的 return dp[n]; } };

四、扩展p78-JZ10青蛙跳台阶扩展问题

跳台阶扩展问题_牛客题霸_牛客网

 动态规划:

//f[n]=f[n-1]+f[n-2]……f[0]
//f[n-1]=f[n-2]+f[n-3]……f[0]
//根据归纳法得f[n]=2*f[n-1]

class Solution { public: int jumpFloorII(int number) { //动归 f[n]表示跳到n台阶一共有几种跳法 //f[n]=f[n-1]+f[n-2]……f[0] //f[n-1]=f[n-2]+f[n-3]……f[0] //根据归纳法得f[n]=2*f[n-1] vector<int> dp(number); dp[0]=1; for(int i=1;i<number;++i) dp[i]=dp[i-1]*2; return dp[number-1]; } };

递归:f[n]=2*f[n-1]我们找到了重复子问题

class Solution { public: int jumpFloorII(int number) { //1或0都是1种 if(number == 1)return 1; //f(n) = 2*f(n-1) return 2 * jumpFloorII(number - 1); } };

数学规律:根据规律f[n]=2^(n-1) 直接用pow函数

class Solution { public: int jumpFloorII(int number) { if(number == 1)return 1; return pow(2,number-1); } };

 五、p124-JZ19 正则表达式匹配

正则表达式匹配__牛客网

 当p[j]==‘.’或者p[j]==s[i]  那么dp[i][j]=dp[i-1][j-1]

当p[j]=='*'的时候,如果p[j-1]==‘.’ 那么dp[i][j-2]||dp[i-1][j-2]……  

                              如果p[j-1]==s[i] 那么dp[i][j-2]||dp[i-1][j-2]||……

//我们可以当*不匹配就是dp[i][j-2] ,或者是*匹配一个然后保留dp[i-1][j] 

class Solution { public: bool match(string s, string p) { //dp[i][j]表示p[0,j]的子串能否匹配s[0,i]的子串 int m=s.size(), n= p.size(); vector<vector<bool>> dp(m+1,vector<bool>(n+1));+s,p=' '+p; //为了方便下标的对应 //分析边界 *可以和前一个组成空串 dp[0][0]=true; for(int j=2;j<=n;j+=2) if(p[j]=='*')dp[0][j]=true; else break; //当p[j]==s[i]||p[j]=='.' dp[i][j]=dp[i-1][j-1] //当p[j]=='*' 此时他可以匹配空,也可以匹配前1个、前两个相同的 //*如果啥也不匹配 dp[i][j-2] 或者是干掉一个然后保留dp[i-1][j] for (int i=1;i<=m;++i) for (int j=1;j<=n;++j) if (p[j]=='*') dp[i][j]=dp[i][j-2]||(p[j-1]==s[i]||p[j-1]=='.')&&dp[i-1][j]; else dp[i][j]=(s[i]==p[j]||p[j]=='.')&&dp[i-1][j-1]; return dp[m][n]; } };

六、p218-JZ42连续子数组的最大和

连续子数组最大和_牛客题霸_牛客网

dp[i]表示以i位置为结尾时的最大子数组和 

#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n; cin>>n; vector<int> nums(n),dp(n); for(int i=0;i<n;++i) cin>>nums[i]; dp[0]=nums[0]; for(int i=1;i<n;++i) dp[i]=max(dp[i-1]+nums[i],nums[i]); cout<<*max_element(dp.begin(),dp.end())<<endl; } 

七、扩展p218-JZ42 连续子数组的最大和(二)

连续子数组的最大和(二)_牛客题霸_牛客网

 与上一题的区别在于我们不仅要统计最大的子数组和,还需要尽量选择最长的,而且还要把他们全都插入到数组里返回(需要记录区间) 

class Solution { public: vector<int> FindGreatestSumOfSubArray(vector<int>& nums) { //连续子数组的最大和 dp[i]表示以i位置为结尾的最大和子数组 int n=nums.size(); vector<int> dp(n); dp[0]=nums[0]; int begin=0;//标记起始位置和i做一段区间 int left=0,right=0;//标记最长的区间 int maxsum=nums[0];//记录最大和 for(int i=1;i<n;++i){ dp[i]=max(nums[i],dp[i-1]+nums[i]); if(nums[i]+dp[i-1]<nums[i]) begin=i;//更新新的起点 if(dp[i]>maxsum||dp[i]==maxsum&&(right-left+1)<(i-begin+1)){ maxsum=dp[i]; left=begin; right=i; } } vector<int> ret; ret.reserve(right-left+1); for(int i=left;i<=right;++i) ret.emplace_back(nums[i]); return ret; } };

八、p231-JZ46 把数字翻译成字符串

 把数字翻译成字符串_牛客题霸_牛客网

//有s[i]单独编码的时候  dp[i]+=dp[i-1]
//当s[i]和s[i-1]一起编码的时候 dp[i]+=dp[i-2] 

class Solution { public: int solve(string nums) { //dp[i]表示以i位置为结尾时一共有多少种编码的可能性 //有s[i]单独编码的时候 dp[i]+=dp[i-1] //当s[i]和s[i-1]一起编码的时候 dp[i]+=dp[i-2] if(nums=="0") return 0; int n=nums.size();+nums; vector<int> dp(n+1); dp[0]=1;//其实没有意义,是为了确保填表的正确 dp[1]=(nums[1]!='0'); for(int i=2;i<=n;++i){ if(nums[i]!='0') dp[i]+=dp[i-1]; int val=(nums[i-1]-'0')*10+nums[i]-'0'; if(10<=val&&val<=26) dp[i]+=dp[i-2]; } return dp[n]; } };

九、p233-JZ47 礼物的最大价值

礼物的最大价值_牛客题霸_牛客网

动态规划 

class Solution { public: int maxValue(vector<vector<int> >& nums) { int m=nums.size(),n=nums[0].size(); //dp[i][j]表示从i j位置选了之后的最大价值 vector<vector<int>> dp(m+1,vector<int>(n+1)); for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) dp[i][j]=max(dp[i-1][j],dp[i][j-1])+nums[i-1][j-1]; return dp[m][n]; } };

 记忆化搜索

class Solution { public: int m,n; int maxValue(vector<vector<int> >& nums) { m=nums.size(),n=nums[0].size(); //dp[i][j]表示从i j位置选了之后的最大价值 vector<vector<int>> memory(m,vector<int>(n)); return dfs(nums,m-1,n-1,memory);//统计最大价值 } int dfs(vector<vector<int> >& nums,int i,int j,vector<vector<int> >& memory){ if(i==0&&j==0) return nums[0][0];//到达了起点 if(memory[i][j]) return memory[i][j]; if(i==0) return memory[0][j]=nums[0][j]+dfs(nums,0,j-1,memory); if(j==0) return memory[i][0]=nums[i][0]+dfs(nums,i-1,0,memory); return memory[i][j]=nums[i][j]+max(dfs(nums,i-1,j,memory),dfs(nums,i,j-1,memory)); } };

十、p312-JZ66 构建乘积数组

 构建乘积数组_牛客题霸_牛客网

使用前缀积和后缀积数组  然后构建结果集 

 vector<int> multiply(vector<int>& nums) { //前缀积和后缀积问题 int n=nums.size(); if(n==1) return {}; vector<int> ret(n); vector<int> dpq(n,1); vector<int> dph(n,1); //前缀积 for(int i=1;i<n;++i) dpq[i]=dpq[i-1]*nums[i-1]; //后缀积 for(int i=n-2;i>=0;--i) dph[i]=dph[i+1]*nums[i+1]; //搞结果集 for(int i=0;i<n;++i) ret[i]=dpq[i]*dph[i]; return ret; } };

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk