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

记忆化搜索专题——算法简介力扣实战应用

目录

1、记忆化搜索算法简介

1.1 什么是记忆化搜索

1.2 如何实现记忆化搜索

1.3 记忆化搜索与动态规划的区别

2、算法应用【leetcode】

2.1 题一:斐波那契数

2.1.1 递归暴搜解法代码

2.1.2 记忆化搜索解法代码

2.1.3 动态规划解法代码

2.2 题二:不同路径

2.2.1 算法原理

2.2.2 记忆化搜索代码 

2.2.3 动态规划代码

2.3 题三:最长递增子序列

2.3.1 算法原理

2.3.2 记忆化搜索代码

2.3.3 动态规划代码

2.4 题四:猜数字大小II

2.4.1 算法原理

 2.4.2 算法代码

2.5 题五:矩阵中的最长递增路径【困难】

2.5.1 算法原理

2.5.2 算法代码


1、记忆化搜索算法简介

1.1 什么是记忆化搜索

记忆化搜索(Memoization)是一种优化搜索算法的技术,主要用于减少重复计算,提高算法效率。它通过存储已经计算过的结果来避免对同一问题的重复计算,特别适用于‌递归算法中存在大量完全重复的递归的情况。

简单来说,记忆化搜索就是带备忘录的递归。

举个例子,当我们使用普通的暴搜递归法求斐波那契数时,意味着每个节点都需要遍历一遍,时间复杂度为O(2^N),但是这其中出现大量完全重复的递归树,大量重复的递归导致时间效率严重降低。这时,我们就可以使用一个“备忘录”所出现过的数据存起来,递归时若遇见重复的问题时,直接从“备忘录”中取值即可,不必再次重复递归。这样一来,我们可将时间复杂优化为线性级别:O(N)。

我们以添加“备忘录”的形式,将数据记忆起来,减少大量重复的递归,这样的暴搜优化( O(2^N) --> O(N) )算法就称为记忆化搜索

注意:

并非所有的递归暴搜都可改为记忆化搜索,只有在递归的过程中,出现了大量完全相同的问题时(并非相同子问题),才可以使用记忆化搜索进行优化。

1.2 如何实现记忆化搜索

  1. 添加备忘录 ---> <可变参数,返回值>
  2. 每次进入递归的时候,瞅一瞅备忘录里面是否已存在想要的结果
  3. 每次递归返回的时候,将结果放到备忘录中存起来

1.3 记忆化搜索与动态规划的区别

其实记忆化搜索与动态规划本质上都是一回事。

  1. 都属于暴力解法(暴搜)
  2. 都是对暴搜的优化:把计算过的值,存起来

但是不同的是:

  1. 记忆化搜索是以递归的形式进行的
  2. 动态规划是以递推(循环)的形式进行的
  3. 记忆化搜索是自顶向下(dfs(n) --> dfs(n-1) 、 dfs(n-2))
  4. 动态规划是自底向上(dp[1] 、 dp[2] --> dp[3] )

2、算法应用【leetcode】

2.1 题一:斐波那契数

. - 力扣(LeetCode)

相信对于斐波那契数的计算,大家都已了然于心,这里就不多废话了,只向大家展示三中不同解法:

  • 递归暴搜解法:O(2^N)
  • 记忆化搜索解法(暴搜优化):O(N) 
  • 动态规划解法(暴搜优化):O(N) 

2.1.1 递归暴搜解法代码

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

2.1.2 记忆化搜索解法代码

class Solution {//记忆化搜索int[] memo;//memorypublic int fib(int n) {memo = new int[31];Arrays.fill(memo, -1);//初始化时,填入不可能出现的值return dfs(n);}public int dfs(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];}
}

2.1.3 动态规划解法代码

class Solution {//动态规划int[] dp;public int fib(int n) {dp = new int[31];dp[0] = 0; dp[1] = 1;for(int i = 2; i <= n; i++) {dp[i] = dp[i - 1] + dp[i - 2];}return dp[n];}
}

2.2 题二:不同路径

. - 力扣(LeetCode)

2.2.1 算法原理

经过分析,可以发现:到达(x,y)位置的路径数=到达(x,y-1)的路径数+到达(x-1,y)的路径数

设计递归函数体:dfs(m,n) = dfs(m,n-1)+dfs(m-1,n)

函数出口:

  1. if(m == 0 || n == 0) return 0;(从下标1开始为有效位置)
  2. if(m== 1&&n ==1) return 1;//特殊处理

 经过验证,纯暴搜解法是会超时的,经分析,问题中出现了大量重复的问题,采取记忆化搜索算法和动态规划进行优化。

2.2.2 记忆化搜索代码 

class Solution {//记忆化搜索int[][] memo;public int uniquePaths(int m, int n) {//从下标1,1开始memo = new int[m + 1][n + 1];return dfs(m, n);}public int dfs(int m, int n) {if(memo[m][n] != 0) return memo[m][n];if(m == 0 || n == 0) {return 0;}if(m == 1 && n == 1) {memo[m][n] = 1;return 1;}memo[m][n] =  dfs(m, n - 1) + dfs(m - 1, n);return memo[m][n];}
}

2.2.3 动态规划代码

class Solution {public int uniquePaths(int m, int n) {//动态规划int[][] dp = new int[m + 1][n + 1];dp[1][1] = 1;for(int i = 1; i < m + 1; i++) {for(int j = 1;j < n + 1; j++) {if(i == 1 && j == 1) continue;dp[i][j] = dp[i][j - 1] + dp[i - 1][j];}}return dp[m][n];}
}

2.3 题三:最长递增子序列

2.3.1 算法原理

因为是最长递增子序列,所以只能从当前位置向后找。

  • 函数头:dfs(pos);//pos位置处的最长子序列
  • 从当前位置pos开始,选出后面位置中最长的子序列len(注意:要求nums[i] > nums[pos]),再得len+1(当加上前位置),就是当前位置的最长子序列。

​ 

2.3.2 记忆化搜索代码

class Solution {//记忆化搜索int n;public int lengthOfLIS(int[] nums) {int ret = 0;n = nums.length;int[] memo = new int[n];for(int i = 0; i < n; i++) {ret = Math.max(ret, dfs(nums, i, memo));}return ret;}public int dfs(int[] nums, int pos, int[] memo) {if(memo[pos] != 0) return memo[pos];int ret = 1;for(int i = pos + 1; i < n; i++) {if(nums[i] > nums[pos]) {ret = Math.max(ret,  dfs(nums, i, memo) + 1);}}memo[pos] = ret;return ret;}
}

2.3.3 动态规划代码

class Solution {//动态规划int n;public int lengthOfLIS(int[] nums) {int ret = 0;n = nums.length;int[] dp = new int[n];Arrays.fill(dp, 1);for(int i = n - 1; i >= 0; i--) {for(int j = i + 1; j < n; j++) {if(nums[i] < nums[j]) {dp[i] = Math.max(dp[i], dp[j] + 1);}}ret = Math.max(dp[i], ret);}return ret;}
}

2.4 题四:猜数字大小II

. - 力扣(LeetCode)

2.4.1 算法原理

暴力枚举出所有可能出现的情况,选出花费最小的最佳策略。

  • 每一种情况都需要选出左右子树中话费金额的最大值(保证能赢)
  • 每种情况话费的金额为:max(左,右)+本身
  • 选出所有情况中花费最小的最佳策略。

 2.4.2 算法代码

class Solution {int[][] memo;public int getMoneyAmount(int n) {memo = new int[n + 1][n + 1];return dfs(1, n);}public int dfs(int s, int e) {int ret = Integer.MAX_VALUE;if(s >= e) {return 0;}if(memo[s][e] != 0) return memo[s][e];for(int i = s; i <= e; i++) {int left = dfs(s, i - 1);int right = dfs(i + 1, e);ret = Math.min(Math.max(left, right) + i, ret);}memo[s][e] = ret;return ret;}
}

2.5 题五:矩阵中的最长递增路径【困难】

. - 力扣(LeetCode)

2.5.1 算法原理

  • 枚举所有节点,选出所有节点中最长的路径
  • 函数设计:dfs(i,j) --> 返回(i,j)位置的最长路径
  • 一个位置的最长路径是固定的 --> 备忘录int[][] memo

2.5.2 算法代码

class Solution {int m, n;int[] dx = {1, -1, 0, 0};int[] dy = {0, 0, 1, -1};int[][] matrix;int[][] memo;//备忘录public int longestIncreasingPath(int[][] matrix_) {matrix = matrix_;m = matrix.length; n = matrix[0].length;memo = new int[m + 1][n + 1];int ret = 0;for(int i = 0; i < m; i++) {for(int j = 0; j < n; j++) {ret = Math.max(ret, dfs(i, j));}}return ret;}public int dfs(int i, int j) {if(memo[i][j] != 0) return memo[i][j];int ret = 1;for(int k = 0; k < 4; k++) {int x = i + dx[k];int y = j + dy[k];if(x >= 0 && x < m && y >= 0 && y < n && matrix[x][y] > matrix[i][j]) {//求出当前位置的最长路径ret = Math.max(ret, dfs(x, y) + 1);}}memo[i][j] = ret;return ret;}
}

END

相关文章:

记忆化搜索专题——算法简介力扣实战应用

目录 1、记忆化搜索算法简介 1.1 什么是记忆化搜索 1.2 如何实现记忆化搜索 1.3 记忆化搜索与动态规划的区别 2、算法应用【leetcode】 2.1 题一&#xff1a;斐波那契数 2.1.1 递归暴搜解法代码 2.1.2 记忆化搜索解法代码 2.1.3 动态规划解法代码 2.2 题二&#xff1…...

【Java】【力扣】83.删除排序链表中的重复元素

题目 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2]示例 2&#xff1a; 输入&#xff1a;head [1,1,2,3,3] 输出&#…...

vue3项目实现全局国际化

本文主要梳理vue3项目实现全项目格式化&#xff0c;例如在我前面文章使用若依创建vue3的项目中&#xff0c;地址&#xff1a;若依搭建vue3项目在导航栏中切换&#xff0c;页面中所有的组件的默认语言随之切换&#xff0c;使用的组件库依旧是element-plus&#xff0c;搭配vue-i1…...

Oracle 19c异常恢复—ORA-01209/ORA-65088---惜分飞

由于raid卡bug故障,导致文件系统异常,从而使得数据库无法正常启动,客户找到我之前已经让多人分析,均未恢复成功,查看alert日志,发现他们恢复的时候尝试resetlogs库,然后报ORA-600 kcbzib_kcrsds_1错误 2024-09-15T17:07:32.55321508:00 alter database open resetlogs 2024-09-…...

【Webpack--000】了解Webpack

&#x1f913;&#x1f60d;Sam9029的CSDN博客主页:Sam9029的博客_CSDN博客-前端领域博主 &#x1f431;‍&#x1f409;若此文你认为写的不错&#xff0c;不要吝啬你的赞扬&#xff0c;求收藏&#xff0c;求评论&#xff0c;求一个大大的赞&#xff01;&#x1f44d;* &#x…...

开源 AI 智能名片链动 2+1 模式 S2B2C 商城小程序与社交电商的崛起

摘要&#xff1a;本文深入探讨了社交电商迅速发展壮大的原因&#xff0c;并分析了开源 AI 智能名片链动 21 模式 S2B2C 商城小程序在社交电商中的重要作用。通过对传统电商与社交电商的对比&#xff0c;以及对各发展因素的剖析&#xff0c;阐述了该小程序如何为社交电商提供新的…...

在线IP代理检测:保护您的网络安全

在互联网飞速发展的今天&#xff0c;越来越多的人开始意识到网络安全和隐私保护的重要性。在线IP代理检测工具作为一种有效的网络安全手段&#xff0c;能够帮助用户识别和检测IP代理的使用情况&#xff0c;从而更好地保护个人隐私和数据安全。本文将详细介绍在线IP代理检测的相…...

【算法】BFS—解开密码锁的最少次数

题目 一个密码锁由 4 个环形拨轮组成&#xff0c;每个拨轮都有 10 个数字&#xff1a; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 。每个拨轮可以自由旋转&#xff1a;例如把 9 变为 0&#xff0c;0 变为 9 。每次旋转都只能旋转一个拨轮的一位数字。 锁的初始数字为 0000 &#xff0c;一个…...

非守护线程会阻止JVM的终止吗

非守护线程会阻止JVM的终止。在Java中&#xff0c;线程分为守护线程&#xff08;Daemon Threads&#xff09;和非守护线程&#xff08;Non-Daemon Threads&#xff0c;也被称为用户线程&#xff09;。这两种线程在JVM终止时表现出不同的行为。 非守护线程是JVM中执行程序主要逻…...

Grafana面板-linux主机详情(使用标签过滤主机监控)

1. 采集器添加labels标签区分业务项目 targets添加labels &#xff08;模板中使用的project标签&#xff09; … targets: [‘xxxx:9100’] labels: project: app2targets: [‘xxxx:9100’] labels: project: app1 … 2. grafana面板套用 21902 模板 演示...

MYSQL数据库基础篇——DDL

DDL&#xff1a;DDL是数据定义语言&#xff0c;用来定义数据库对象。 一.DDL操作数据库 1.查询 ①查询所有数据库 输入&#xff1b; 得到结果&#xff1a; ②查询当前数据库 输入&#xff1b; 例如执行下面语句&#xff1a; 2.创建 输入 然后展示数据库即可得到结果&…...

Springboot 集成 Swing

背景 Springboot 在 Java 给 Java 开发带来了极大的便利&#xff0c;那么如何把它集成到 Swing GUI 编程项目中&#xff0c;使得 GUI 编程更加高效&#xff1f;本人简单做了一下尝试&#xff0c;完成一个 demo &#xff0c;贴出来供大家参考 具体步骤 创建一个 spring boot …...

枚举算法总结

枚举算法&#xff08;Enumeration Algorithm&#xff09;是一种简单而直接的算法设计策略&#xff0c;它通过列出问题的所有可能情况&#xff0c;逐一进行验证&#xff0c;直到找到问题的解。这种算法适用于问题的解空间不是太大&#xff0c;可以通过遍历所有情况来找到答案的情…...

编译 Android 11源码

参考小米6 lineageos官方编译文档&#xff1a;https://wiki.lineageos.org/devices/sagit/build 单独编译 framework 以LineageOS18.1&#xff08;Android 11&#xff09;为例&#xff1a; 1、在源码根目录执行&#xff1a; make framework-minus-apex 2、用生成的framewo…...

时间复杂度计算 递归(solve2 后续)

原帖 最近校内比较忙&#xff0c;更新缓慢&#xff0c;致歉。 这里函数每次都需要遍历 h h h 和 m m m 之间的数&#xff08;复杂度 O ( n ) O(n) O(n)&#xff09;&#xff0c;所以和 solve1 略有不同。仍然假设 T ⁡ ( n ) \operatorname{T}(n) T(n) 表示 m − h 1 n…...

Nginx:高性能Web服务器与反向代理的深度剖析

Nginx&#xff1a;高性能Web服务器与反向代理的深度剖析 Nginx&#xff08;发音为“engine X”&#xff09;是一款轻量级但功能强大的Web服务器和反向代理服务器&#xff0c;以其高并发处理能力、低内存占用和灵活的扩展性在互联网项目中得到了广泛应用。本文将深入探讨Nginx…...

JavaSE - 面向对象编程03

01 多态 01_01 认识多态 01_02 多态的好处和缺点 【1】好处&#xff1a;① 可以解耦合&#xff0c;扩展性更强&#xff0c;父类引用指向的子类对象可以随时切换&#xff0c;而后面的逻辑代码并不需要更改。 ② 使用父类引用可以作为方法的形参或返回类型来接收一切子类对象。…...

变电站缺陷数据集8307张,带xml标注和txt标注,可以直接用于yolo训练

变电站缺陷数据集8307张&#xff0c; 带xml标注和txt标注&#xff0c;可以直接用于yolo训练&#xff0c;赠附五个脚本 变电站缺陷数据集 数据集概述 变电站缺陷数据集是一个专门针对变电站设备和环境缺陷检测的图像数据集。该数据集包含了8307张经过标注的图像&#xff0c;旨…...

Redis的存储原理和数据模型

一、Redis是单线程还是多线程呢&#xff1f; 我们通过跑redis的代码&#xff0c;查看运行的程序可以得知&#xff0c;Redis本身其实是个多线程&#xff0c;其中包括redis-server&#xff0c;bio_close_file&#xff0c;bio_aof_fsync&#xff0c;bio_lazy_free&#xff0c;io_t…...

Linux 文件与目录操作命令详解

文章目录 前言创建文件1. touch2. vim 文件内容显示3. cat4. more5. less6. head7. tail 文件&#xff08;目录&#xff09;复制、删除和移动8. cp9. rm10. mv 压缩文件与解压缩11. gzip12. zip 和 unzip 创建目录13. mkdir 删除目录14. rmdir 改变工作目录15. cd16. pwd 显示目…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...