08. 算法之递归算法

news2024/11/25 0:56:39

前言

递归,字面意思是递出去,拿回来,通过不断递过去,拿回来的过程,将每次调用结果保存起来,最后实现循环调用。递归在某些情况下会极大降低我们编程的复杂度。是软件开发工程师一定要掌握的技能。

1. 概念

递归:在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。也就是说,递归算法是一种直接或者间接调用自身函数或者方法的算法。
在这里插入图片描述

2. 本质

递归,去的过程叫"递",回来的过程叫”归“。递是调用,归是结束后回来。是一种循环,而且在循环中执行的就是调用自己。递归调用将每次返回的结果存在栈帧中

2.1 递归三要素

  1. 递归结束条件
  2. 函数的功能,这个函数要干什么
  3. 函数等价公式,递归公式,一般是每次执行之间,或者个数之间逻辑关系

3. 小例子

3.1 循环实现

@Test
public void test1(){
    for (int i = 0; i < 5; i++) {
        System.out.println("你好呀");
    }
}

3.2 递归实现

void print(int count,String msg){
    //结束条件
    if (count<=0){
        return;
    }
    //函数功能
    System.out.println(msg);
    //等价公式
    print(--count,msg);
}

@Test
public void test2(){
    print(5,"你好呀");
}

4. 经典案例

4.1 斐波那契数列

0、1、1、2、3、5、8、13、21、34、55…

4.2 规律:

从第3个数开始,每个数等于前面两个数的和

4.3 递归分析

  1. 函数功能:返回n的前两个数之和
  2. 结束条件:从第三个数开始,n<=2
  3. 等价公式:fun(n)=fun(n-1)+fun(n-2)

4.4 代码实现

@Test
public void test3(){
    int febnum = febnum(10);
    System.out.println(febnum);
}

int febnum(int n){
    if (n<0){
        System.out.println("输入错误");
    }
    //结束条件
    if (n==0 || n==1){
        return n;
    }
    //等价公式 函数功能
    return febnum(n-1)+febnum(n-2);
}

5. 时间复杂度

斐波那契数列 普通递归解法为O(2^n)

6. 优缺点

6.1 优点:

代码简单

6.2 缺点:

占用空间较大,如果递归太深,可能会发生栈溢出,可能会有重复计算通过备忘录或递归的方式去优化(动态规划)

7. 应用

递归作为基础算法,应用非常广泛,比如在二分查找、快速排序、归并排序、树的遍历上都有使用递归回溯算法、分治算法、动态规划中也大量使用递归算法实现

8. 斐波那契优化

通过上面的算法可以看到,我们实际做了大量的重复计算,比如计算f(5)需要计算f(4) 和 f(3),但是在计算f(4)的时候,又需要计算f(3)和f(2),又因为这是层层递归的,数字一大,递归的层数,计算的次数就会迅速扩张。为此,我们可以优化一下处理逻辑

8.1 动态规划

8.1.1 逻辑分析

斐波那契数的边界条件是 F(0) = 0 和 F(1) = 1当 >1 时,每一项的和都等于前两项的和,因此有如下递推关系:
F(n)= F(n -1) + F(n - 2)
由于斐波那契数存在递推关系,因此可以使用动态规划求解。动态规划的状态转移方程即为上述递推关系边界条件为 F(0) 和 F(1)。根据状态转移方程和边界条件,可以得到时间复杂度和空间复杂度都是 O(n)的实现。
由于 F(n)只和F(n - 1)与 F( - 2)有关,因此可以使用滚动组思想] 把空间复杂度优化成 0(1)

8.1.2 代码验证

public int fib(int n) {
	//因为数会很大,为此对结果取模,保证最终计算结果不会太大
    static final int MOD = 1000000007;

    if (n < 2) {
        return n;
    }
    int p = 0, q = 0, r = 1;
    for (int i = 2; i <= n; ++i) {
        p = q;
        q = r;
        r = (p + q)%MOD;
    }
    return r;
}

8.1.3 复杂度分析

  1. 时间复杂度为O(n)
  2. 空间复杂度为O(1)

8.2 矩阵快速幂

8.2.1 前置知识

  1. 如需求数据 a 的幂次,此处 a 可以为数也可以为矩阵,常规做法需要对a进行不断的乘积即 a * a * a * … 此处的时间复杂度将为 O(n)
  2. 以3^10为例
3^10=3*3*3*3*3*3*3*3*3*3

    =9^5 = 9^4*9

    =81^2*9

    =6561*9
  1. 基于以上原理,我们在计算一个数的多次幂时,可以先判断其幂次的奇偶性,然后:
  2. 如果幂次为偶直接 base(底数) 作平方,power(幂次) 除以2
  3. 如果幂次为奇则底数平方,幂次整除于2然后再多乘一次底数
  4. 对于以上涉及到 [判断奇偶性] 和 [除以2] 这样的操作。使用系统的位运算比普通运算的效率是高的,因此可以进一步优化:把 power % 2 == 1 变为 (power & 1) == 1。把 power = power / 2 变为 power = power >> 1

8.2.2 逻辑分析

在这里插入图片描述

8.2.3 代码验证

package org.wanlong.recursion;

class Solution {
    public int fib(int n) {
        //矩阵快速幂
        if (n < 2) {
            return n;
        }
        //定义乘积底数
        int[][] base = {{1, 1}, {1, 0}};
        //定义幂次
        int power = n - 1;
        int[][] ans = calc(base, power);
        //按照公式,返回的是两行一列矩阵的第一个数
        return ans[0][0];
    }

    //定义函数,求底数为 base 幂次为 power 的结果
    public int[][] calc(int[][] base, int power) {
        //定义变量,存储计算结果,此次定义为单位阵
        int[][] res = {{1, 0}, {0, 1}};

        //可以一直对幂次进行整除
        while (power > 0) {
            //1.若为奇数,需多乘一次 base
            //2.若power除到1,乘积后得到res
            //此处使用位运算在于效率高
            if ((power & 1) == 1) {
                res = mul(res, base);
            }
            //不管幂次是奇还是偶,整除的结果是一样的如 5/2 和 4/2
            //此处使用位运算在于效率高
            power = power >> 1;
            base = mul(base, base);
        }
        return res;
    }

    //定义函数,求二维矩阵:两矩阵 a, b 的乘积
    public int[][] mul(int[][] a, int[][] b) {
        int[][] c = new int[2][2];
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                //矩阵乘积对应关系
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
            }
        }
        return c;
    }
}

8.2.4 复杂度分析

  1. 时间复杂度 O(logn)
  2. 空间复杂度O(1)

8.3 备忘录

8.3.1 逻辑分析

前面提到计算复杂度高很大原因是重复计算,为此,很容易想到的是,我们将计算结果保存起来,下次先看看有没有计算过,如果计算过,就不重复计算了

8.3.2 代码验证

package org.wanlong.recursion;

import java.util.HashMap;
import java.util.Map;

/**
 * @author wanlong
 * @version 1.0
 * @description:
 * @date 2023/5/30 11:02
 */
public class SolutionWithMap {

    Map<Integer, Integer> result = new HashMap<>();

    int febnum(int n) {
        if (n < 0) {
            System.out.println("输入错误");
        }
        //结束条件
        if (n == 0 || n == 1) {
            return n;
        }
        //判断是否计算过
        if (result.get(n) != null) {
            return result.get(n);
        }
        int febnum1 = febnum(n - 1);
        int febnum2 = febnum(n - 2);
        result.put(n - 1, febnum1);
        result.put(n - 2, febnum2);
        //等价公式 函数功能
        int res = febnum1 + febnum2;
        result.put(n, res);
        return res;
    }


}

测试类验证

 //测试备忘录
 @Test
 public void test6(){
     int fib = new SolutionWithMap().febnum(10);
     System.out.println(fib);
 }

8.3.3 复杂度分析

  1. 时间复杂度O(n^2)
  2. 空间复杂度O(n)

以上,本人菜鸟一枚,如有错误,请不吝指正。

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

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

相关文章

Linux—实操篇:vi和vim编辑器

1.vi和vim基本介绍 Linux系统会内置vi文本编辑器 vim具有程序编写的能力&#xff0c;可以看做是vi的增强版本&#xff0c;被程序员广泛使用 2、vi和vim常用的三种模式 2.1、正常模式 以vim打开一个档案就直接进入一般模式了(这是默认的模式)。在这个模式中&#xff0c;你可…

溯源取证 - 流量分析 中等难度

使用工具&#xff1a; Brim 链接: https://www.brimdata.io/download/ Networkminer 链接: https://www.netresec.com/?pageNetworkMiner Wireshark Strings ida pro 知识点&#xff1a; 通过本篇文章&#xff0c;学习ssh协议特点、学习流量导出文件、学习简单的逆向分析、…

卫星定位北斗芯片AT6558一款高性能BDS/GNSS多模卫星导航接收机SOC单芯片

1 芯片简介 AT6558R是一款高性能BDS/GNSS多模卫星导航接收机SOC单芯片,片上集成射频前端&#xff0c; 数字基带处理器&#xff0c;32位的RISCCPU&#xff0c;电源管理功能。 芯片支持多种卫星导航系统&#xff0c;包括中国的北斗卫星导航系统BDS&#xff0c;美国的GPS,俄罗斯 的…

Mysql DDL执行方式-pt-osc介绍 | 京东云技术团队

1 引言 大家好&#xff0c;接着上次和大家一起学习了《MySQL DDL执行方式-Online DDL介绍》&#xff0c;那么今天接着和大家一起学习另一种MySQL DDL执行方式之pt-soc。 在MySQL使用过程中&#xff0c;根据业务的需求对表结构进行变更是个普遍的运维操作&#xff0c;这些称为…

elasticsearch分词,排序,分页,高亮简单示例

目录 1. 创建ES实体2. 创建查询实体3. 查询方法实现3.1 总体代码3.2 构建查询条件3.2.1 关键词分词 3.3 高亮处理4.总体查询代码 记&#xff0c;写一个简单的es分词demo,es版本6.8.12 如果使用es7有些方法可能会有所改变&#xff0c;请参考7的文档 es安装教程&#xff1a;http:…

SUSE系统上安装HANA

一:安装SUSE操作系统 1.1 准备安装镜像 SLE-15-SP1-安装程序-DVD-x86_64-GM-DVD1 SLE-15-SP1-软件包-x86_64-GM-DVD1 SAP HANA安装文件 IMDB_SERVER20_032_0-80002031.SAR 1.2 引导系统 1.3 选择要安装的产品 SUSE Linux Enterprise Server for SAP Applications 15 SP…

Stable Diffusion教程(5) - 文生图教程

配套视频教程&#xff1a; https://v.douyin.com/UyHNfYG/ 文生图界面标注如下 1 提示词和反向提示词 提示词内输入的东西就是你想要画的东西&#xff0c;反向提示词内输入的就是你不想要画的东西 提示框内只能输入英文&#xff0c;所有符号都要使用英文半角&#xff0c;词语…

企业级信息系统开发讲课笔记4.5 掌握Spring Boot多环境配置

文章目录 零、学习目标一、项目进行多环境配置的必要性二、使用Profile文件进行多环境配置&#xff08;一&#xff09;创建Spring Boot项目&#xff08;二&#xff09;创建多环境配置文件1、全局配置文件改名2、模拟开发环境3、模拟测试环境4、模拟生产环境 &#xff08;三&…

Unity基础 音频组件以及音频播放

在游戏开发中&#xff0c;声音是一个重要的环节。Unity中的声音组件可以帮助开发者轻松地控制游戏中音频的播放、音量、循环等属性&#xff0c;从而实现更好的游戏体验。本文将详细介绍Unity声音组件的相关概念和技术&#xff0c;以及其在游戏、影视等领域的广泛应用和发展前景…

银行联行号-联行号api接口-联行号数据源

接口地址&#xff1a; https://登录后显示/api/180/348(支持:http/https) 数据源&#xff1a;https://www.wapi.cn/source/8.html 网站地址&#xff1a;https://www.wapi.cn 返回格式&#xff1a;json,xml 请求方式&#xff1a;GET,POST 请求说明&#xff1a; 银行联行号-联行…

数据集:T-Drive(北京出租车轨迹数据)

1 数据来源 T-Drive trajectory data sample - Microsoft Research 2 数据介绍 数据集包含了2008年2月2日至2月8日期间在北京市内的10,357辆出租车的GPS轨迹。总共包含约1500万个GPS点&#xff0c;轨迹总里程达到了900万公里。 图1显示了两个连续点之间的时间间隔和距离间隔…

Apache 配置和应用

目录 构建虚拟 Web 主机 Options指令解释 Options指令常用选项 AllowOverride指令解释&#xff1a; 地址限制策略&#xff1a; httpd服务支持的虚拟主机类型包括以下三种: 基于域名的虚拟主机 1&#xff0e;为虚拟主机提供域名解析 2.为虚拟主机准备网页文档 3.添加虚拟…

【服务器】springboot实现HTTP服务监听

文章目录 前言1. 本地环境搭建1.1 环境参数1.2 搭建springboot服务项目 2. 内网穿透2.1 安装配置cpolar内网穿透2.1.1 windows系统2.1.2 linux系统 2.2 创建隧道映射本地端口2.3 测试公网地址 3. 固定公网地址3.1 保留一个二级子域名3.2 配置二级子域名3.2 测试使用固定公网地址…

Mysql 异常,“Cause: com.mysql.cj.jdbc.exceptions.MySQLTimeoutException”

Cause: com.mysql.cj.jdbc.exceptions.MySQLTimeoutException: Statement cancelled due to timeout or client request 简言&#xff1a;这种异常从字面翻译过来&#xff1a;mysql 请求链接超时&#xff0c;具体超时是什么原因导致的&#xff0c;可以根据情况分析下。 异常详…

【黄啊码】PHP商城中的积分任务系统实现

大家好&#xff0c;我是黄啊码&#xff0c;前几天有位小伙伴问我&#xff0c;商城中的任务系统是怎么实现的&#xff1f; 积分作为一种营销手段&#xff0c;被广泛运用于线上/线下的产品中&#xff0c;以此来增加用户对于产品的粘性。比如天猫积分可以用来兑换商品&#xff0c…

uni-app通过vue.config.js在项目中配置跨域代理

其实这个 如果你用nginx去配肯定再好不过 不过 一般大家也都不想把开发环境弄那么复杂 最好还是在项目中配置 那么 我们选择项目跟目录右键 选择 使用命令行窗口打开所在目录 在新弹出的命令行中引入依赖 npm install http-proxy-middleware --save-dev然后我们的依赖就进来…

【通信接口】CAN总线协议

目录 一、什么是CAN 1、CAN 的概念 2、节点构成&#xff08;CAN 总线通信模型&#xff09; 3、差分信号&#xff08;电平特性&#xff09; 4、CAN 总线的特点 二、CAN 总线协议的通信过程 1、发送过程 2、接收过程 3、概括 三、CAN 通信帧的分类 一、什么是CAN 1、C…

易基因:全基因组ChIP-seq分析揭示细菌转录因子PhoB的基因内结合位点|mBio

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 细菌编码许多转录因子&#xff08;transcription factor&#xff0c;TF&#xff09;&#xff0c;这些转录因子通过与启动子周围的DNA结合并调控RNA聚合酶&#xff08;RNAP&#xff09;全…

微服务架构打造的供应链系统、采购配送系统,支持SaaS模式

一、开源项目简介 haohan-scm 介绍 基于pig微服务架构打造 供应链系统&#xff0c;采购配送系统。为客户提供仓储管理、订单管理、打单、货源采购、分拣、配送等系统功能。 二、开源协议 使用AGPL-3.0开源协议 三、界面展示 系统截图 四、功能概述 基于pig微服务架构打…

电脑重装系统需要多长的时间

电脑重装系统是一个涉及多个步骤和因素的过程&#xff0c;所需的时间会因个体差异和系统配置而异。本文将解析电脑重装系统所需的时间&#xff0c;并提供一些因素和建议&#xff0c;帮助您对整个过程有一个准确的预期。 工具/原料&#xff1a; 系统版本&#xff1a;windows8系…