dfs记忆化搜索刷题 + 总结

dfs记忆化搜索刷题 + 总结

文章目录

记忆化搜索 vs 动态规划

1. 记忆化搜索:有完全相同的问题/数据保存起来,带有备忘录的递归
2.记忆化搜索的步骤:
1、添加一个备忘录 <可变参数,返回值>
2、递归每次返回的时候,将结果放入备忘录中
3、在每次进入递归的时候,往备忘录中查找一下
3. 记忆化搜索和常规的动态规划都是动态规划,暴搜 -> 记忆化搜索 -> 动态规划
4. 有大量重复的问题才能改成记忆化搜索
在这里插入图片描述

斐波那契数

题目链接

在这里插入图片描述

题解

1. 创建一个备忘录
2. 把备忘录中的值初始化为斐波那契数中不可能出现的的值-1
3. 在每次递归完成之前,把值存入备忘录中
4. 在每次进入递归的时候,查找一下备忘录中是否有值,有值就直接返回,相当于剪枝

代码

classSolution{public:// 记忆化搜索int memo[31];intfib(int n){memset(memo,-1,sizeof memo);returndfs(n);}intdfs(int n){if(memo[n]!=-1){return memo[n];}if(n ==0|| n ==1){ memo[n]= n;return n;} memo[n]=dfs(n-1)+dfs(n-2);return memo[n];}};// 动态规划classSolution{public:int dp[31];intfib(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];}};

不同路径

题目链接

在这里插入图片描述

题解

1. 函数头的设计,只需要i和j的坐标
2. 返回条件:i == 0 || j == 0都是返回0
i == 1 && j == 1 第一个点返回1
3. 记忆化搜索就是创建一个二维的备忘录,在递归之前往备忘录中查找一下,返回之前把结果都存在备忘录中
在这里插入图片描述

代码

// 记忆化搜索classSolution{public:int memo[102][102];intuniquePaths(int m,int n){returndfs(m,n);}intdfs(int m,int n){// 往备忘录中查找一下if(memo[m][n])return memo[m][n];// 返回条件if(m ==0|| n ==0)return0;// 第一个点if(m ==1&& n ==1){ memo[m][n]=1;return1;} memo[m][n]=dfs(m-1,n)+dfs(m,n-1);return memo[m][n];}};// 动态规划classSolution{public:intuniquePaths(int m,int n){ vector<vector<int>>dp(m+1,vector<int>(n+1)); 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];}};

最长递增子序列

题目链接

在这里插入图片描述

题解

1. 记忆化搜索:每次枚举以pos位置为起点的最长递增子序列,让pos+1位置的值和pos位置比较大小,如果大于就加一,函数头需要nums和pos位置,函数体需要pos+1位置到n-1位置,dfs会完成找到最大递增子序列的工作,+1是加上本身
2. 动态规划:从后往前添加状态,第一个循环用来枚举位置,第二个循环用来比较大小,更新最长递增子序列到dp[i]中,内层循环结束,更新一下最长的子序列,因为不知道哪个位置是最大的
在这里插入图片描述

代码

// 记忆化搜索classSolution{public:int memo[2510];intlengthOfLIS(vector<int>& nums){int ret =1;// 每次以i位置为起点往后搜索for(int i =0;i < nums.size();i++){ ret =max(dfs(nums,i),ret);}return ret;}intdfs(vector<int>& nums,int pos){if(memo[pos]!=0)return memo[pos];int ret =1;for(int i = pos+1;i < nums.size();i++){if(nums[i]> nums[pos]) ret =max(ret,dfs(nums,i)+1);} memo[pos]= ret;return memo[pos];}};// 动态规划classSolution{public:intlengthOfLIS(vector<int>& nums){int n = nums.size();// 最短的子序列都是1 vector<int>dp(n,1);int ret =1;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);}} ret =max(ret,dp[i]);}return ret;}};

猜数字大小II

题目链接

在这里插入图片描述

题解

1. 暴搜 -> 记忆化搜索
2. 算法原理:在区间[1,n]固定一个点i,分为左右区间,寻找花费最小金钱达到必胜的方案,方案数是不止实例一那一种的,然后在左右枝中寻找所花费金额的最大值才能胜利
3. 函数头需要传参左右区间,函数体需要实现寻找多种方案中的最小花费和当前方案下的最大金钱,出现了重复的数据可以使用记忆化搜索
在这里插入图片描述

代码

classSolution{public:int memo[201][201];intgetMoneyAmount(int n){// 计算出所有方案数中的最小花费returndfs(1,n);}intdfs(int left,int right){if(left >= right)return0;if(memo[left][right]!=0)return memo[left][right];int ret = INT_MAX;for(int head = left;head <= right;head++){int x =dfs(left,head-1);int y =dfs(head+1,right); ret =min(ret,max(x,y)+ head);} memo[left][right]= ret;return ret;}};

矩阵中的最长递增路径

题目链接

在这里插入图片描述

题解

1. 算法原理:从一个点开始dfs,暴力枚举出每一个递增的路径,返回其中最长的路径即可
2. dfs函数的设计,需要i,j坐标去搜索每一个位置
3. 记忆化数组,如果出现相同的路径,不用再次dfs,直接返回即可
在这里插入图片描述

代码

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

总结

1. 记忆化搜索就是先把暴力的dfs先写出来,然后加一个备忘录优化
2. 记忆化搜索也和常规的动态规划是一样的,即记忆化搜索也可以改为动态规划的代码
3. 出现大量重复的数据可以使用记忆化搜索,记忆化搜索可以使原本O(2^n)时间复杂度降为O(n)

Read more

【C++笔记】STL详解:vector容器的实现

【C++笔记】STL详解:vector容器的实现

前言:         在学习了vector类的基本使用的前提下,本文将重点分析vector类的常用接口及其应用实现。          一、vector成员变量          vector本质上是一个动态数组,通过原生指针来实现底层维护,为了使得STL接口调用的统一性,我们需要将原生指针重命名为迭代器。          其核心目的是:将数据结构(容器)与操作(算法)分离,并通过一种统一的接口(迭代器)将它们粘合在一起。          成员变量分析 template <class T> class vector { public: // 将原生指针重命名为迭代器,实现接口统一 typedef T* iterator; typedef const T* const_iterator; private: iterator _start; // 指向目前使用空间的头 iterator _finish; // 指向目前使用空间的尾 iterator _end_of_storage; // 指向目前可用空间的尾 };          成员变量分析:

By Ne0inhk
Java 集合框架详解:从原理到实战,一篇吃透所有常用集合

Java 集合框架详解:从原理到实战,一篇吃透所有常用集合

Java 集合框架是开发中最常用的工具类集合,它统一管理了各类数据存储结构(数组、链表、红黑树等),提供了便捷的增删改查方法,解决了数组固定长度、操作繁琐的痛点。本文从集合框架整体结构出发,详解核心集合类的原理、用法和适用场景,搭配实战代码,让你既能理解底层逻辑,又能在开发中灵活选型。 一、集合框架整体结构:两大核心阵营 Java 集合框架主要分为 Collection(单列集合) 和 Map(双列集合) 两大阵营,所有集合类都围绕这两个核心接口展开: 1. 核心结构概览 注:图片来自面试鸭 2. 核心接口区别 * Collection:存储单个元素的集合,提供统一的元素操作方法(add、remove、iterator 等); * Map:存储键值对(key-value),key 唯一,value 可重复,提供根据 key 操作

By Ne0inhk
springboot-java民宿房源预订网站vue

springboot-java民宿房源预订网站vue

目录 * 技术栈与架构 * 核心功能模块 * 特色与优化 * 扩展性设计 * 开发技术 * 源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式! 技术栈与架构 SpringBoot-Java民宿房源预订网站采用前后端分离架构,后端基于SpringBoot框架实现RESTful API,前端使用Vue.js构建动态交互界面。数据库选用MySQL存储房源、用户、订单等核心数据,结合Redis缓存高频访问数据(如热门房源)。系统通过JWT实现用户认证与授权,集成支付宝/微信支付接口完成交易闭环。 核心功能模块 房源管理:支持房东发布、编辑房源信息,包括图文详情、价格日历、设施标签等;采用Elasticsearch实现多条件筛选(位置、价格、房型等)。 预订系统:用户可查看实时房源状态,选择日期并在线支付;后端通过分布式锁防止超卖,定时任务自动处理未支付订单。 评价与社交:用户入住后可发表评价,系统支持评分统计与内容审核;集成地图API展示房源位置周边信息。 特色与优化 前端采用Vue Router实现SPA无刷新跳转,Ax

By Ne0inhk
飞算 JavaAI 深度体验:开启 Java 开发智能化新纪元

飞算 JavaAI 深度体验:开启 Java 开发智能化新纪元

个人主页:♡喜欢做梦 欢迎  👍点赞  ➕关注  ❤️收藏  💬评论 目录 一、引言 二、飞算 JavaAI 初印象与功能概览 (一)初识 (二)核心功能模块概览 三、智能代码生成功能深度体验 (一)基础场景测试 (二)复杂业务逻辑场景 (三)代码生成功能总结 四、代码优化建议功能测评 (一)测试用例准备 (二)优化建议 (三)进一步复杂代码测试 (四)代码优化功能总结 五、故障诊断与修复功能实践 (一)模拟常见 Java 故障场景 一、引言 在当今软件开发领域,Java 凭借其跨平台性、稳定性等优势,长期占据重要地位。然而,

By Ne0inhk