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

news2024/11/15 14:09:54

目录

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;//memory
    public 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150858.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络模型的保存与读取

文章目录 一、模型的保存二、文件的加载三、模型加载时容易犯的陷阱 一、模型的保存 方式1:torch.save(vgg16, “vgg16_method1.pth”) import torch import torchvision.modelsvgg16 torchvision.models.vgg16(pretrainedFalse) torch.save(vgg16, "vgg16_method1.pth…

oracle数据库启动

文章目录 背景一、步骤1.登录oracle用户2.启动监听服务3.启动数据库 背景 oracle数据库启动 一、步骤 1.登录oracle用户 代码如下&#xff08;示例&#xff09;&#xff1a; su - oracle2.启动监听服务 代码如下&#xff08;示例&#xff09;&#xff1a; lsnrctl start成…

【C++】STL----vector常见用法

&#x1f525;个人主页&#x1f525;&#xff1a;孤寂大仙V &#x1f308;收录专栏&#x1f308;&#xff1a;C从小白到高手 &#x1f339;往期回顾&#x1f339;&#xff1a;[C]string类 &#x1f516; 流水不争&#xff0c;争的是滔滔不息。 文章目录 一、vector的介绍vector…

MATLAB绘图基础8:双变量图形绘制

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 8.双变量图形绘制 8.1 散点图 散点图用于显示两个变量间的关系&#xff0c;每个数据点在图上表示为一个点&#xff0c;一个变量在 X {\rm X} X轴&#xff0c;一个变量在 Y {\rm Y} Y轴&#…

【Python报错已解决】AttributeError: ‘DataFrame‘ object has no attribute ‘append‘

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

暴雨信息|《2024 年全球人工智能趋势报告》发布,GPU仍是AI发展最大关键之一

全球著名调研机构WEKA近日正式发布《2024年全球人工智能趋势报告》&#xff0c;该报告是基于全球1500人工智能决策者的深度调查&#xff0c;覆盖金融、政府、医疗保健等多个行业&#xff0c;解锁了人工智能领域的关键见解和策略。 人工智能正成为许多组织战略的一个基本面&…

滑动窗口(8)_最小覆盖字串

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 滑动窗口(8)_最小覆盖字串 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题…

6.C++程序中的基本数据类型

数据类型是指在C中用于声明不同类型变量或函数的一个系统或抽象或者是一个分类&#xff0c;它决定了变量存储占用的内存空间以及解析存储的位模式。其实数据类型可以理解为固定内存大小的别名&#xff0c;是创建变量的模具&#xff0c;具体使用哪种模具&#xff08;包括自定义&…

基于深度学习的文本情感原因提取研究综述——论文阅读

前言 既然要学习情感分析&#xff0c;那么肯定还要了解情感原因对抽取的发展历程&#xff0c;所以我又搜了一篇研究综述&#xff0c;虽然是2023年发表的&#xff0c;但是里面提及到的历程仅停留到2022年。这篇综述发布在TASLP期刊&#xff0c;是音频、声学、语言信号处理的顶级…

进程间的通信-信号量

信号量 1.资源竞争 资源竞争 : 当多个进程同时访问共享资源时&#xff0c;会产生资源竞争&#xff0c;最终最导致数据混乱临界资源 : 不允许同时有多个进程访问的资源&#xff0c;包括硬件资源(CPU、内存、存储器以及其他外围设备)与软件资源(共享代码段、共享数据结构)临界区…

有关JS下隐藏的敏感信息

免责声明&#xff1a;本文仅做分享&#xff01; 目录 JavaScript 介绍 核心组成 工具 FindSomething ** 浏览器检查 ** LinkFinder URLfinder ** SuperSearchPlus ** ffuf ParasCollector waymore Packer Fuzzer JS逆向 应用&#xff1a; 小结&#xff1a; Ja…

基于Python+SQLite的课程管理系统

系统需求简介 1.1需求分析 实现一个具体的课程管理系统。按照软件工程思路设计简化的专业课数据库&#xff0c;尽量模拟现有专业课程一个学期的选课排课原型实际情况。&#xff08;注&#xff1a;本系统由本人单独设计、开发完成&#xff09; 1.2 数据结构需求分析 课程管理…

NAND闪存:迎来新的发展机遇

2024年&#xff0c;存储市场正在经历着动态的变化&#xff0c;其中包括合同价格的上涨、制造商营收的增长以及多项技术上的突破。在这个背景下&#xff0c;主要的存储公司正在为新的挑战做准备&#xff0c;尤其是在NAND闪存领域即将面临转型的情况下。 扩展阅读&#xff1a;20…

PMData:人工智能之运动记录数据集

简介 在这个数据集中&#xff0c;我们展示了 PMData 数据集&#xff0c;旨在将传统的生活记录与体育活动记录相结合。这样的数据集可以开发几个有趣的分析应用程序&#xff0c;例如&#xff0c;可以使用额外的运动数据来预测和分析日常发展&#xff0c;如人的体重和睡眠模式&a…

数据飞轮:打造业务增长的持续循环

在当今数据驱动的世界中&#xff0c;企业必须利用数据的力量才能保持竞争力。然而&#xff0c;仅仅收集和分析数据是不够的&#xff1b;企业必须能够从他们的数据中创造一个持续增长的循环&#xff0c;才能保持成功。其中一种方法就是创建数据飞轮。接下来让我们来探讨一下什么…

centos7如何连接网络 centos7wifi连接

这段时间重新学习 Linux 知识&#xff0c;用的是笔记本&#xff0c;连接的是无良房东家的 WiFi&#xff0c;IP地址经常变动。每次都要修改 Xshell 的配置才能连上虚拟机。效率很低。 为此&#xff0c;必须要解决这个 IP 地址经常变动的事情&#xff01;这里讲解的版本是&#…

Java集成gdal 处理解析tiff和shp数据

1. 配置 gdal 1.1. 官网下载 这个是因为你电脑是 win64 位才选择哦&#xff5e; 下载这个&#xff0c;然后解压 1.2. 复制这个压缩包下的 ddl 文件 可以按照类型复制&#xff0c;然后复制到你的 java jDK 文件夹下 1.3. 找到你的 java jdk 文件夹 不知道 java 的文件夹位置…

数字签名和CA数字证书的核心原理

看了蛋老师的视频就很容易理解了&#xff0c;首先对服务器的公钥和信息进行哈希运算得到一个短字符串&#xff0c;然后用CA机构中的私钥对这一短字符串进行加密就得到了一个数字签名&#xff0c;然后就这个数字签名放到数字证书中&#xff0c;同时服务器的公钥也放在数字证书中…

NFT Insider #148:The Sandbox 推出 SHIBUYA Y3K 时尚系列,Azuki 进军动漫 NFT 领域

市场数据 加密艺术及收藏品新闻 Infinex 新推 NFT 系列首四日销售额破4000万美元 尽管顶级 NFT 系列表现不佳&#xff0c;Infinex 的最新 NFT 系列在首四日内销售额已超过 4000 万美元。Infinex 是一个非托管平台&#xff0c;提供轻松访问链上协议和 dApp。 Infinex Core 的…

Day69补 前后端分离思想

ajax前后端分离 前后端分离处理&#xff1a;前端------&#xff08;数据&#xff09;-----服务端----&#xff08;数据&#xff09;-----前端-----动态改变页面的内容 1.json 1、JSON&#xff1a;由于JSON易读以及纯文本格式的特性&#xff0c;可以非常容易地与其他程序进行沟通…