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

【递归、回溯、搜索】专题六:记忆化搜索

目录

一*、斐波那契数

二、不同路径

三、最长递增子序列

四、猜数字大小II

五、矩阵中的最长递增路径


一*、斐波那契数

509. 斐波那契数 - 力扣(LeetCode)

有些题记忆化搜索与动规等同,就像这题

解法一:递归

思路如下:
递归,O 2^n,画出递归展开树,我们发现,总会有些重复计算,比如n=5时d(3)就求了很多次,如果n越大,那么重复的计算会非常多。那么我们是不是可以用一个备忘录储存一下计算过的值,如果后边要拿这个数,那么就能直接拿到不用再递归计算了,从而将时间复杂度从指数级别降到线性级别这就是记忆化搜索。

递归代码如下:
 

class Solution {
public:int fib(int n) {return dfs(n);}int dfs(int n){if(n==0||n==1)return n;return dfs(n-1)+dfs(n-2);}
};

解法二:记忆化搜索(避免重复运算,复杂度降低到线性)

记忆化搜索(备忘录递归)(自顶向下)O(n)

备忘录具体如何实现?

我们需要建立可变参数与计算值的映射关系,所以需要哈希表的思想

而我们本题创建一个数组就可以了。

记忆化搜索实现如下:

class Solution {//刚需31,不能用={-1}初始化,全局变量这样处理,只会第一个是-1int memo[31];
public:int fib(int n) {memset(memo,-1,sizeof memo);return dfs(n);}int dfs(int n){//往备忘录看一眼if(memo[n]!=-1){return memo[n];}//和递归终点初始化一样,往备忘录塞数if(n==0||n==1){memo[n]=n;return memo[n];}//往备忘录塞数memo[n]=dfs(n-1)+dfs(n-2);return memo[n];}
};

解法三:动态规划(自下上顶),常规的动态规划和记忆化搜搜本质差别不大。

dp实现如下:

class Solution {int dp[31];
public:int fib(int n) {dp[0]=0,dp[1]=1;for(int i=2;i<=n;++i){dp[i]=dp[i-1]+dp[i-2];}return dp[n];}
};

二、不同路径

62. 不同路径 - 力扣(LeetCode)

思路如下:

纯递归会超时,优化为记忆化搜索

注意该题相当于从1,1的位置出发

到达某点的方法,等于到上面那个点方法+到左边那个点方法之和

代码实现如下:

解法一:记忆化搜索

class Solution {int memo[101][101];
public:int uniquePaths(int m, int n) {return dfs(m, n);}int dfs(int m, int n) {if (memo[m][n] != 0) {return memo[m][n];}//上,左边界全部处理为0if (m == 0 || n == 0){return memo[m][n];}if (m == 1 && n == 1) {memo[m][n] = 1;return memo[m][n];}memo[m][n] = dfs(m - 1, n) + dfs(m, n - 1);return memo[m][n];}
};

解法二:dp,还是动规代码更好看

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

三、最长递增子序列

300. 最长递增子序列 - 力扣(LeetCode)

先看看暴力如何做

思考递归每一层都在干什么

1.暴力就是从每一个元素为起点,后边遇到数字变大的就更新path,递归每层我们都要创建一个path,然后计算这个位置往后的最大的,返回这个path

搞清每次都在干什么就很好写了,不过该代码会超时,因为是n叉树,复杂度近乎于n^n,非常高

class Solution {
public:int lengthOfLIS(vector<int>& nums) {int ret=0;for(int i=0;i<nums.size();++i){ret=max(ret,dfs(nums,i));}return ret;}int dfs(vector<int>& nums,int pos){int path=1;for(int i=pos+1;i<nums.size();++i){if(nums[i]>nums[pos]){//不能path+=dfs(nums,i) or path=dfs(nums,i)+1//因为这里for循环遍历在暴搜这个位置往后的可能最大值,每次需要比较path=max(path,dfs(nums,i)+1);}}return path;}
};

2.记忆化优化,因为后边遇到更大数字要更新path,如果memo里有这个数字,那么我们只需要加上这个最大数字位置(可能会有重复)往后最大的递增子序列长度就行。创建一个备忘录,dfs函数开头先检查这个位置记录了没有,有返回,没有进入dfs内部,计算完这个位置后在备忘录记录。

class Solution {
public:int lengthOfLIS(vector<int>& nums) {vector<int> memo(nums.size());int ret=0;for(int i=0;i<nums.size();++i){ret=max(ret,dfs(nums,i,memo));}return ret;}int dfs(vector<int>& nums,int pos,vector<int>& memo){//查找备忘录,看一下这个位置有没有记录if(memo[pos]!=0)return memo[pos];int path=1;for(int i=pos+1;i<nums.size();++i){if(nums[i]>nums[pos]){//不能path+=dfs(nums,i) or path=dfs(nums,i)+1//因为这里for循环遍历在暴搜这个位置往后的可能最大值,每次需要比较path=max(path,dfs(nums,i,memo)+1);}}memo[pos]=path;return path;}
};

3.dp,动规后续会出一个专栏专门讲解

因为我求一个位置最长子序列,都要知道这个位置往后的情况,那么我们dp就得从后往前更新,因为往后才是最底的那个部分

class Solution {
public:int lengthOfLIS(vector<int>& nums) {//每个都得初始是1,不能是0,不能只初始最后一个位置是1//可能有的数往后都是比它小的,那它也不能是0,而是1int n=nums.size();vector<int> dp(n,1);int ret=0;for(int i=n-1;i>=0;--i){for(int j=i+1;j<n;++j){if(nums[j]>nums[i]){dp[i]=max(dp[i],dp[j]+1);}}//得到i位置往后最大递增子串,判断ret=max(ret,dp[i]);}return ret;}
};

四、猜数字大小II

375. 猜数字大小 II - 力扣(LeetCode)

没记错的话,贪心章节也会提及这题

有了第一道猜数字,可能会考虑二分,如果答案是10,那么这个策略来猜,

花销是很大的。所以二分并不是最好的策略,因为我们要的不是最小次数,而是最小保证赢的金额,也就是往大值里找最小值。

问题的核心在于,答案的不确定性,所以为了确保你的钱够付得起所有结果,你得准备的钱一定得是你这个分支,往更大的地方猜测去准备你的本金,这样就算数是更小部分,我们准备的钱也足够我们获胜。

博弈,枚举从1~n当作头,然后往下递归处理子问题

递归每层处理,都往大的地方考虑,求下层所有递归结果的,里的最小值

记忆化搜索+dfs实现

class Solution {int memo[201][201];
public:int getMoneyAmount(int n) {return dfs(1,n);}int dfs(int left,int  right){if(left>=right)return 0;if(memo[left][right]!=0)return memo[left][right];int ret=INT_MAX;for(int head=left;head<=right;++head){//x:左子树处理结果 y:右子树处理结果int x=dfs(left,head-1);int y=dfs(head+1,right);//max(x,y)保证赢需要往大了考虑ret=min(ret,head+max(x,y));}//更新该区间的保证赢的最少花费memo[left][right]=ret;return ret;}
};

五、矩阵中的最长递增路径

329. 矩阵中的最长递增路径 - 力扣(LeetCode)

有了前面的铺垫,这道困难题就易如反掌了

class Solution {int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1},m,n;int memo[201][201];
public:int longestIncreasingPath(vector<vector<int>>& matrix) {m=matrix.size(),n=matrix[0].size();int ret=0;for(int i=0;i<m;++i){for(int j=0;j<n;++j){ret=max(ret,dfs(matrix,i,j));}}return ret;}int dfs(vector<vector<int>>& matrix,int i,int j){if(memo[i][j]!=0)return memo[i][j];int path=1;for(int k=0;k<4;++k){int x=i+dx[k],y=j+dy[k];if(x>=0&&x<m&&y>=0&&y<n&&matrix[x][y]>matrix[i][j]){path=max(path,dfs(matrix,x,y)+1);}}memo[i][j]=path;return path;}
};

此专栏完结撒花*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。

感谢收看。

http://www.dtcms.com/a/558327.html

相关文章:

  • 网站页面描述怎么写咸阳鑫承网站建设
  • 如何在百度举报网站桂林市临桂区
  • 一个可以做行程的网站网站虚拟主机1g
  • 网站标题和关键词一样网页版微信登录不了怎么解决
  • 2015年做啥网站能致富wordpress 导出export.php
  • 开网站做商城怎么样北京ui网页设计培训
  • WindoWs 系统管理批处理脚本
  • 【大模型训练】zero1与zero
  • 网站特效怎么做品牌设计公司vi设计
  • 图片墙网站源码网站建设售后服务方案
  • 《算法通关指南:数据结构和算法篇 --- 顺序表相关算法题》--- 1.移动零,2.颜色分类
  • 呼和浩特市做网站公司好的电子工程网络信息技术专业
  • php网站开发账号密码西安十大广告设计公司
  • 南山做网站的公司网站改版是否有影响
  • 叙述网站的建设意义所在建设互联网站
  • wordpress能发多少邮件东莞关键词优化排名
  • Apache Spark算法开发指导-特征转换RobustScaler
  • 广东省省考备考(第一百三十九天11.1)——判断推理、资料分析、数量关系(强化训练)
  • 自己建网站有什么用网站运营需要哪些知识
  • 网站 app建设开发合作协议有没有做推文的网站
  • 企业做网站公司排名口碑硬件开发平台
  • 德州做网站的公司南昌网站建设哪家就好
  • 【python】装饰器
  • 培训计划--linux基础操作
  • 做一网站要什么时候开始企业网站的建设包括哪些
  • 023数据结构之线段树——算法备赛
  • 做化工回收的 做那个网站广东新闻发布会
  • 《信息系统项目管理师》2024 年上第 2 批次案例分析题及解析
  • 华为OD机试双机位A卷 - 插队 (C++ Python JAVA JS GO)
  • 裕华区建设局网站九天智能建站软件