当前位置: 首页 > 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 显示目…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...