记忆化搜索【上】

news2024/9/23 11:17:15

509. 斐波那契数

题目链接:斐波那契数

递归(暴搜)

斐波那契数列,最传统的解法,采用递归:

class Solution {
public:
    int fib(int n)
    {
        return dfs(n);
    }

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

n = 4的时候,虽然不是满二叉树,但是高度有4层,时间复杂度可以理解为O(2n)。

image-20240831205231259

记忆化搜索

这里递归展开,就会发现,做了很多次重复的递归,在此基础上可以将其优化,将递归过的数字,放入“备忘录”,当再次要递归该数的时候,直接从备忘录来取即可,这就是所谓的记忆化搜索。

  1. 添加一个备忘录
  2. 递归返回时,将结果放入备忘录
  3. 进入递归时,检查备忘录是否有
class Solution {
public:
    int memo[31];
    int fib(int n)
    {
        //-1不可能出现在备忘录当中, 设为初始值
        memset(memo, -1, sizeof(memo));
        return dfs(n);
    }

    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];
    }
};

动态规划

动态规划,五步走:

  1. 确定状态表示(dfs函数的含义)
  2. 推导状态转移方程(dfs函数体)
  3. 初始化(dfs函数递归出口)
  4. 确定填表顺序(填写备忘录顺序)
  5. 确定返回值(主函数如何调用dfs)

这五步和上面的记忆化搜索能一一对应起来,因为它们本质都是一样的,都将已经计算的值存起来

class Solution {
public:
    int dp[31];
    int fib(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];
    }
};

62. 不同路径

题目链接:62. 不同路径 - 力扣(LeetCode)

递归(暴搜)

image-20240831214045538

交给dfs到达(i, j)有多少种方法,这题就是到达(m, n)有多少种方法,函数头即是:dfs(m, n)

假设要到达菱形这个位置,只需要知道到达两个绿圆圈有多少种方法即可,因为只有必须要通过这两个位置,即dfs(i-1, j) + dfs(i, j-1)

image-20240831214338853

将起点设置为(1, 1)更方便遍历,那么当i == 0 || j == 0的时候,无需递归;
(1, 1)为起点,也无需递归,即这两个就是出口。

class Solution {
public:
    int uniquePaths(int m, int n)
    {
        return dfs(m, n);
    }

    int dfs(int i, int j)
    {
        if(i == 0 || j == 0)
        {
            return 0;
        }
        if(i == 1 && j == 1)
        {
            return 1;
        }
        return dfs(i-1, j) + dfs(i, j-1);
    }
};

暴搜会超时

记忆化搜索

这里递归展开,也会出现很多重复的,所以可以将暴搜转换成记忆化搜索:

  1. 定义一个“备忘录”
  2. 递归前检查“备忘录”
  3. 返回之前将结果存入“备忘录”
class Solution {
public:
    int uniquePaths(int m, int n)
    {
        vector<vector<int>> memo(m+1, vector<int>(n+1));
        return dfs(m, n, memo);
    }

    int dfs(int i, int j, vector<vector<int>>& memo)
    {
        if(memo[i][j] != 0)
        {
            return memo[i][j];
        }
        if(i == 0 || j == 0)
        {
            return 0;
        }
        if(i == 1 && j == 1)
        {
            memo[i][j] = 1;
            return 1;
        }
        memo[i][j] = dfs(i-1, j, memo) + dfs(i, j-1, memo);
        return memo[i][j];
    }
};

动态规划

就是将递归版本改为迭代版本

class Solution {
public:
    int uniquePaths(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];
    }
};

300. 最长递增子序列

题目链接:300. 最长递增子序列 - 力扣(LeetCode)

递归

直接暴力枚举所有递增子序列,然后选出里面最长的

image-20240902224954596

代码解释:

  • 不知道是哪个起点的子序列最长,一次for循环
  • 递归函数,以当前位置为头,寻找下一个位置的子序列,一次for循环
  • 无需设置出口处,因为有for循环,遍历结束自动出来了
class Solution {
public:
    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)
    {
        //要算自己
        int ret = 1;
        for(int i = pos+1; i < nums.size(); i++)
        {
            if(nums[i] > nums[pos])
            {
                ret = max(ret, dfs(i, nums) + 1);
            }
        }
        return ret;
    }
};

会超时,多叉树

记忆化搜索

上图可见,递归的时候,会出现重复元素的递归,所有可以采用记忆化搜索的方式

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

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

动态规划

  • dp表的含义:以某个位置为起点的最长递增子序列的长度
  • pos位置的时候,依赖的是pos后面的值,所以填表顺序是从后往前填
  • 要算上自己,所以初始的值为1
class Solution {
public:
    int lengthOfLIS(vector<int>& nums)
    {
        int n = nums.size();
        vector<int> dp(n, 1);
        int ret = 0;
        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;
    }
};

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

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

相关文章

搭建核心架构网络项目(局域网)

一个基础项目的搭建 一、项目简介 这个项目主要就是最基础的一个局域网&#xff0c;模拟现实企业的网络架构&#xff0c;确保网络的安全性&#xff0c;通过VLAN划分实现不同部门或用户组的隔离等。 下图是我们这次要搭建的局域网拓扑图。&#xff08;左边为财务部门&#xff0…

[Algorithm][综合训练][kotori和n皇后][取金币][矩阵转置]详细讲解

目录 1.kotori和n皇后1.题目链接2.算法原理详解 && 代码实现 2.取金币1.题目链接2.算法原理详解 && 代码实现 3.矩阵转置1.题目链接2.算法原理详解 && 代码实现 1.kotori和n皇后 1.题目链接 kotori和n皇后 2.算法原理详解 && 代码实现 解法&…

Yapi部署文档

Yapi是高效、易用、功能强大的API管理平台&#xff0c;旨在为开发、产品、测试人员提供更优雅的接口管理服务 官网地址&#xff1a;Yapi 环境&#xff1a; l Git l NodeJs&#xff08;7.6&#xff09; l Mongodb&#xff08;2.6&#xff09; 1、 NodeJs的安装 获取资源 …

嵌入式硬件-ARM处理器架构,CPU,SOC片上系统处理器

多进程空间内部分布图&#xff1a;注意&#xff1a;创建线程实际使用兑取空间&#xff0c;栈区独立 ARM处理器架构&#xff1a; 基于ARM920T架构的CPU:以下时哈佛结构ARM920T是ARM公司的32位RISC&#xff08;精简指令集计算机&#xff09;处理器内核。它具有以下特点&#xff1…

day-47 组合

思路 回溯&#xff1a;利用个dfs方法递归调用&#xff0c;每个元素有选或不选两种抉择&#xff0c;当选中元素个数等于k时&#xff0c;将链表p加入答案&#xff0c;当idsn且选中元素个数小于n时&#xff0c;直接返回 解题过程 每次选中元素调用dfs方法后记得还原 Code class…

【数据结构】顺序表和链表——顺序表(包含丰富算法题)

文章目录 1. 线性表2. 顺序表2.1 概念与结构2.2 分类2.2.1 静态顺序表2.2.2 动态顺序表 2.3 动态顺序表的实现2.4 顺序表算法题2.4.1 移除元素2.4.2 删除有序数组中的重复项2.4.3 合并两个有序数组 2.5 顺序表问题与思考 1. 线性表 线性表&#xff08;linear list&#xff09;…

vivado 定义时间约束

定义时间约束和 例外情况 在本实验中&#xff0c;您将学习两种为设计创建约束的方法。您必须使用 AMD Vivado™IDE中包含的AMD Kintex™7 CPU网表示例设计。 第一步&#xff1a;打开示例项目 1.打开Vivado IDE。 •在Linux上&#xff1a; 1.更改实验室材料的存储目录。 cd&…

HarmonyOS--后台代理提醒

一、概述 HarmonyOS提供后台代理提醒功能&#xff0c;在应用退居后台或退出后&#xff0c;计时和提醒通知功能被系统后台代理接管。后台代理提醒就是由系统后台进程代理应用的提醒功能。后台代理提醒服务通过reminderAgentManager模块提供提醒定义、创建提醒、取消提醒等能力。…

zdppy+vue3+onlyoffice文档管理系统实战 20240902 上课笔记 登录功能优化

遗留问题 1、登录以后跳转最近文档2、如果用户没有登录应该自动跳转登录页面3、如果用户的token校验失败&#xff0c;应该自动调整登录界面4、按回车键自动跳转登录页面 登录以后跳转最近文档 const router useRouter() router.push("/")实际代码&#xff1a; c…

C++篇:C向C++迈进(下)

目录 引言 缺省参数 1.缺省参数的概念 2.缺省参数的分类 2.1 全缺省 2.2 半缺省 3.注意事项 函数重载 1.函数重载的定义 2.函数重载的基本规则 3.函数重载的运用场景 引用 1.引用的概念 2.引用的主要特性 3.常引用 4.引用的使用场景 4.1 函数参数传递 4.2 函…

计算机网络-VRRP基础概念

回顾一下以前我们学习的网络通信基础&#xff0c;终端通过交换机可以相互进行通信&#xff0c;而如果是不同网段间的通信需要经过三层网关&#xff0c;网关进行路由寻址和转发&#xff0c;所以基本的网络结构就是终端--交换机--路由器网关--网络出口--Internet。 一、VRRP虚拟路…

逻辑回归算法详解

目录 原理推导 逻辑回归求解 项目实战--信用卡欺诈检测 数据分析与预处理 数据读取与分析 样本不均衡解决方案 特征标准化 下采样方案 交叉验证 模型评估方法 正则化惩罚 逻辑回归模型 参数对结果的影响 混淆矩阵 分类阈值对结果的影响 过采样方案 SMOTE数据生…

点击率预测模型Embedding层的学习和训练

导读&#xff1a; 本文将简要介绍推荐模型的发展历史&#xff0c;现状&#xff0c;和下一步的研究趋势。并重点介绍针对embedding数据的模型训练及优化。主要包含以下几大部分内容&#xff1a; CTR预测模型&#xff08;CTR Models&#xff09;连续值处理&#xff08;Continuou…

OpenAI“草莓项目”最快今年秋季发布!苹果将于9月10号推出首款AI iPhone|AI日报

文章推荐 吴恩达辞任Landing AI CEO&#xff0c;专注AI投资&#xff1f;数学家斯蒂芬预言哲学家引领AI未来&#xff5c;AI日报 与人类产生情感共鸣&#xff1f;数字华夏推出“夏澜”人形机器人&#xff1b;微软Azure AI语音服务推出虚拟人形象&#xff5c;AI日报 今日热点 …

行程问题

某直升机原定以260公里的时速飞往目的地&#xff0c;因任务紧急&#xff0c;飞行时速提高到360公里&#xff0c;结果提前1小时到达&#xff0c;则总的航程是&#xff08; &#xff09;公里。 A 900 B 936【正确答案】 C 1200 D 1296 第一步&#xff0c;本题考察行程问题&#x…

自行车租赁管理系统设计与实现

第三章 系统分析 3.1 系统可行性分析 可行性研究(Feasibility Study)是通过对项目的主要内容和配套条件&#xff0c;如市场需求、资源供应、建设规模、工艺路线、设备选型、环境影响、资金筹措、盈利能力等&#xff0c;从技术、经济、工程等方面进行调查研究和分析比较&…

使用mybatis对学生管理系统的完整功能实现

一、什么是mybatis: MyBatis 是一个优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c;将接口和 Java 的 POJOs(Pla…

大赛题目公布,鸣志电器,对不起了

大家好&#xff0c;我是博主&#xff0c;夏目 即9/2发布组织第一届 电机电磁仿真大赛后&#xff0c;有很多朋友跃跃欲试&#xff0c;但也有不少顾虑。 跃跃欲试的原因是&#xff0c;对于这种新颖的活动&#xff0c;参与其中&#xff0c;也是一种乐趣&#xff0c;一种经验的积…

什么是I2C总线?

1.什么是I2C&#xff1f; 1.1 I2C的由来 在电视机内部电路中&#xff0c;众多功能需要用到许多集成电路IC来实现&#xff0c;包括主控器件微控制器和众多外围设备器件。这些器件相互之间要传递数据信息&#xff0c;那么就需要用导线相互连接&#xff0c;如此众多IC器件的互连&…

ArcGIS Pro 发布松散型切片

使用ArcGIS Pro发布松散型切片问题&#xff0c;有时候会出现切片方案写了松散型&#xff0c;但是自动切片完成后依然是紧凑型的问题&#xff0c;这时候可以采用手动修改然后再切片的方式。 1. 发布切片服务 选择手动切片方式 2. 手动修改服务的切片方案文件 修改cache服务…