算法:记忆化搜索

文章目录

  • 记忆化搜索
    • 斐波那契数列
  • 例题
    • 不同路径
    • 最长递增子序列
    • 猜数字大小
    • 矩阵中的最长递增路径

记忆化搜索的原理其实很简单,简单来说就是对暴力搜索的一些优化,因此整体上来讲难度不高

记忆化搜索

所谓记忆化搜索,直白来说就是一个带有备忘录的递归

如何实现记忆化搜索?

  1. 添加一个备忘录
  2. 递归每次返回的时候,都把结果放在备忘录当中
  3. 每次进行递归前,都到备忘录中看一看

下面用一个经典题目诠释记忆化搜索的意义

斐波那契数列

在这里插入图片描述

  1. 递归
class Solution 
{
public:
    // 递归
    int fib(int n) 
    {
        if(n == 0 || n == 1) return n;
        return fib(n - 1) + fib(n - 2);
    }
};
  1. 动态规划
class Solution 
{
public:
    // 动态规划
    int fib(int n) 
    {
        if(n == 0 || n == 1)
            return n;
        vector<int> v(n + 1);
        v[0] = 0, v[1] = 1;
        for(int i = 2; i <= n; i++)
            v[i] = v[i - 1] + v[i - 2];
        return v[n];
    }
};
  1. 记忆化搜索
class Solution 
{
public:
    // 记忆化搜索
    int memo[31];
    int fib(int n) 
    {
        // 先到备忘录中看看
        if(memo[n] != 0)
            return memo[n];
        if(n == 0 || n == 1)
        {
            memo[n] = n;
            return memo[n];
        }
        return fib(n - 1) + fib(n - 2);
    }
};

从上面这个例题能感觉出来,记忆化搜索其实就是在递归的基础上进行了一些优化,没有什么本质性的新增内容,基于这个原因,用下面的例题来进一步学习记忆化搜索

例题

不同路径

在这里插入图片描述
暴力搜索

class Solution 
{
public:

    int dfs(int m, int n, int p, int q)
    {
        if(m > p || n > q) return 0;
        if(m == p && n == q) return 1;
        return dfs(m + 1, n, p, q) + dfs(m, n + 1, p, q);
    }

    int uniquePaths(int m, int n) 
    {
        return dfs(0, 0, m - 1, n - 1);
    }
};

采用记忆化搜索进行一定程度的优化

class Solution 
{
public:
    int arr[101][101];
    int dfs(int m, int n, int p, int q)
    {
        if(arr[m][n] != 0) return arr[m][n];
        if(m > p || n > q) return 0;
        if(m == p && n == q) return 1;
        int down = dfs(m + 1, n, p, q);
        int right = dfs(m, n + 1, p, q);
        arr[m + 1][n] = down;
        arr[m][n + 1] = right;
        return down + right;
    }

    int uniquePaths(int m, int n) 
    {
        return dfs(0, 0, m - 1, n - 1);
    }
};

最长递增子序列

在这里插入图片描述

暴力搜索

class Solution
{
public:
	vector<int> path;
	int maxSize;
	int lengthOfLIS(vector<int>& nums)
	{
		dfs(0, nums, INT_MIN);
		return maxSize;
	}

	void dfs(int pos, vector<int>& nums, int prev)
	{
		maxSize = max(maxSize, (int)path.size());

		for (int i = pos; i < nums.size(); i++)
		{
			if (nums[i] > prev)
			{
				path.push_back(nums[i]);
				dfs(i + 1, nums, nums[i]);
				path.pop_back();
			}
		}
	}
};

记忆化搜索

class Solution 
{
public:
    int memo[2501];

    int lengthOfLIS(vector<int>& nums) 
    {
        int ret = 0;
        for(int i = 0; i < nums.size(); i++)
        {
            ret = max(ret, dfs(i, nums));
        }
        return ret;
    }

    int dfs(int pos, vector<int>& nums)
    {
        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(i, nums) + 1);
            }
        }
        memo[pos] = ret;
        return ret;
    }
};

猜数字大小

在这里插入图片描述
暴力搜索

class Solution 
{
public:
    int getMoneyAmount(int n) 
    {
        return dfs(1, n);
    }

    int dfs(int begin, int end)
    {
        if(begin >= end) return 0;
        int res = INT_MAX;
        // 选一个节点作为根节点
        for(int i = begin; i <= end; i++)
        {
            // 找左子树花费的钱
            int left = i + dfs(begin, i - 1);
            // 找右子树花费的钱
            int right = i + dfs(i + 1, end);
            res = min(res, max(left, right));
        }
        return res;
    }
};

记忆化搜索优化

class Solution 
{
public:
    vector<vector<int>> memo;
    int getMoneyAmount(int n) 
    {
        memo.resize(n + 1, vector<int>(n + 1));
        return dfs(1, n);
    }

    int dfs(int begin, int end)
    {
        if(begin >= end) return 0;
        if(memo[begin][end] != 0) return memo[begin][end];
        int res = INT_MAX;
        // 选一个节点作为根节点
        for(int i = begin; i <= end; i++)
        {
            // 找左子树花费的钱
            int left = i + dfs(begin, i - 1);
            // 找右子树花费的钱
            int right = i + dfs(i + 1, end);
            res = min(res, max(left, right));
        }
        memo[begin][end] = res;
        return res;
    }
};

矩阵中的最长递增路径

在这里插入图片描述
记忆化搜索

class Solution 
{
public:
    int m, n;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    vector<vector<int>> memo;
    int longestIncreasingPath(vector<vector<int>>& matrix) 
    {
        m = matrix.size();
        n = matrix[0].size();
        memo.resize(m, vector<int>(n));
        int res = 0;
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < n; j++)
            {
                res = max(res, dfs(i, j, matrix));
            }
        }
        return res;
    }

    // 从第i行和第j列的这个元素开始的最长递增路径
    int dfs(int i, int j, vector<vector<int>>& matrix)
    {
        if(memo[i][j] != 0) return memo[i][j];
        int ret = 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])
            {
                ret = max(ret, 1 + dfs(x, y, matrix));
            }
        }
        memo[i][j] = ret;
        return ret;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mock测试数据

1.下载一个jar 架包 地址&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1G5rVF5LlIYpyU-_KHsGjOA?pwdab12 提取码&#xff1a;ab12 2.配置当前电脑java环境变量 3.在同一文件目录下创建json 数据4.在终端切换到当前目录下启动服务&#xff0c; java -jar ./moco-r…

HIS医疗项目

文章目录 医疗项目简介HIS项目介绍HIS架构解析HIS业务流程图HIS项目架构图 HIS组件解析——服务支撑 内存设置为4G或以上部署NGINX服务部署web安装JDK部署Elasticsearch安装ik中文分词器 部署rabbitmq部署MySQL服务安装MySQL服务建库、授权用户导入数据 部署Redis测试Redis 部署…

Redis篇---第五篇

系列文章目录 文章目录 系列文章目录前言一、持久化有两种,那应该怎么选择呢?二、怎么使用 Redis 实现消息队列?三、说说你对Redis事务的理解前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,…

医院数字化LIS(检验信息系统)源码

临床检验信息管理系统&#xff08;LIS&#xff09;是利用计算机连接医疗设备&#xff0c;通过计算机信息处理技术&#xff0c;将医院检验科或实验室的临床检验数据进行自动收集、存储、处理、提取、传输和交换&#xff0c;满足所有授权用户的功能需求。 一、系统概述 1.LIS&am…

新材料企业ERP有几种?能帮助企业解决哪些问题

在我们的生活当中会遇到各种各样的新材料&#xff0c;这些新材料对应不同的制造工艺、品质检验标准、生产工序、制造设备等。有些新材料企业的营销渠道不止一个&#xff0c;各个营销平台的经营策略和商品维护流程各不相同&#xff0c;而这也使得日常的管理工作量较大。 经过多…

盘点52个Python各行各业管理系统源码Python爱好者不容错过

盘点52个Python各行各业管理系统源码Python爱好者不容错过 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 源码下载链接&#xff1a;https://pan.baidu.com/s/1pcP-94UY_57sAd2oDB3i6Q?pwd8888 提取码&#xff1a;8888 项目名…

【Linux】Linux进程间通信(三)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【Linux】…

Spring过滤器和拦截器的区别

&#x1f4d1;前言 本文主要Spring过滤器和拦截器的区别的问题&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&#x…

基础课8——中文分词

中文分词指的是将一个汉字序列切分成一个一个单独的词。分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。在英文的行文中&#xff0c;单词之间是以空格作为自然分界符的&#xff0c;而中文只是字、句和段能通过明显的分界符来简单划界&#xff0c;唯独词没有一个…

飞熊领鲜参加「第十届中国产业数字化大会」获创新企业数字化百强

11月16日至17日&#xff0c;托比网“第十届中国&#xff08;南京&#xff09;产业数字化大会”在南京举行。作为“中国&#xff08;南京&#xff09;电子商务大会”的一部分&#xff0c;本次会议由江苏省商务厅、南京市人民政府指导&#xff0c;南京市商务局、南京市鼓楼区人民…

Linux | 安装openGauss数据库

Linux 安装openGauss数据库 今天我们来安装一下国产数据库openGauss~~ 下载openGauss 首先在官网下载对应的安装包&#xff0c;我们这里下载LInux 极简版来演示安装 下载后,使用root用户上传到Linux ,这边上传到/usr/local/目录下, 使用root 用户创建安装目录 mkdir /usr/l…

2023年中职“网络安全“—Linux系统渗透提权③

2023年中职"网络安全"—Linux系统渗透提权③ Linux系统渗透提权任务环境说明&#xff1a;1. 使用渗透机对服务器信息收集&#xff0c;并将服务器中SSH服务端口号作为flag提交&#xff1b;2. 使用渗透机对服务器信息收集&#xff0c;并将服务器中主机名称作为flag提交…

IO流-数据流

一&#xff0c;IO流-数据流 二&#xff0c;数据输出流 三&#xff0c;案例 package BigDecimal;import java.io.DataOutputStream; import java.io.FileOutputStream;public class DATaOutputStreamss {public static void main(String[] args) {try ( //1,创建一个数据输出流…

全球地表水数据集JRC Global Surface Water Mapping Layers v1.4

简介&#xff1a; JRC Global Surface Water Mapping Layers产品&#xff0c;是利用1984至2020年获取的landsat5、landsat7和landsat8的卫星影像&#xff0c;生成分辨率为30米的一套全球地表水覆盖的地图集。用户可以在全球尺度上按地区回溯某个时间上地表水分的变化情况。产品…

吉林省土木建筑学会建筑电气分会及吉林省建筑电气情报网学术交流年会-安科瑞 蒋静

11月9-10日&#xff0c;吉林省土木建筑学会建筑电气分会及吉林省建筑电气情报网学术交流年会在吉林长春隆重举办。安科瑞电气股份有限公司作为智慧用电产品供应商受邀参会&#xff0c;为参会人士展示了安科瑞能源物联网云平台、电力运维云平台、智慧消防云平台、预付费管理云平…

酷柚易汛ERP - 系统初始化操作指南

1、应用场景 重新初始化将会清空系统数据&#xff0c;恢复至新系统初始创建的状态&#xff0c;且不可逆转&#xff0c;请谨慎操作&#xff01; 初始化系统需要验证管理员密码&#xff0c;密码输入正确后即可开始初始化系统

CSS滚动捕获 scroll-snap-align

CSS滚动捕获 scroll-snap-align 看到 align, 就条件反射想到对齐方式, 嗯猜对了. 不过要先看一下若干名词介绍 scroll-snap-align 指定了盒子的 snap position, 即盒子 snap area 和滚动容器的 snapport 的对齐方式. 这个属性是定义在滚动元素上, 而不是滚动容器上 语法 这个…

C++类中public 和 protected 和 private访问权限 struct和class的区别 类成员设置为私有自己控制权限

public 和 protected 和 private访问权限 public 公共权限 类内可以访问 类外可以访问 protected 保护权限 类内可以访问 类外不可以访问 儿子可以访问父亲中的保护内容如父亲的车 private 私有权限 类内可以访问 类外不可以访问 儿子不可以访问父亲的私有权限内容如不想…

使用 React Flow 构建一个思维导图应用

思维导图是围绕共同主题或问题将思想、概念、信息或任务分组的视觉表示。思维导图应用是一种软件应用&#xff0c;允许您创建、可视化和组织您的思想、想法和信息作为思维导图。本文将向您展示如何实现自己的思维导图应用程序。 在我们开始之前&#xff0c;我想向您展示一下我们…

【C++11】多线程库 {thread线程库,mutex互斥锁库,condition_variable条件变量库,atomic原子操作库}

在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和平台相关的&#xff0c;比如windows和linux下各有自己的接口&#xff0c;这使得代码的可移植性比较差。 //在C98标准下&#xff0c;实现可移植的多线程程序 —— 条件编译 #ifdef _WIN32CreateThread(); //在windows系…