递归学习第一个课


一、递归定义

基本定义

  1. 函数自己调用自己(通俗第一印象)
  2. 大问题可以拆分小问题(拆分,边界)
  3. 大问题与小问题的关系(递归关系)
    1. 为什么拆分小问题?
      1. 小问题更容易求解
      2. 大问题与小问题内部结果一样
      3. 大问题与小问题入参不一样

核心概念

  1. 终止条件或边界条件
  2. 递归关系:大问题与小问题的关系

例题

  • 700. 二叉搜索树中的搜索
  • /**
     * Definition for a binary tree node.
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode() {}
     *     TreeNode(int val) { this.val = val; }
     *     TreeNode(int val, TreeNode left, TreeNode right) {
     *         this.val = val;
     *         this.left = left;
     *         this.right = right;
     *     }
     * }
     */
    //递归解法
    class Solution {
        public TreeNode searchBST(TreeNode root, int val) {
            if(root == null){
                return null;
            }
    
            if(root.val == val){
                return root;
            }
    
            if(val<root.val){
                return searchBST(root.left,val);
            }else{
                return searchBST(root.right,val);
            }
        }
    }
    
    
    //迭代替换递归解法
    class Solution {
        public TreeNode searchBST(TreeNode root, int val) {
            while (root != null) {
                if (root.val == val) {
                    return root;
                }
                if (val < root.val) {
                    root = root.left;
                } else {
                    root = root.right;
                }
            }
            return null;
        }
    }

二、递归思想分类

1、缓存

  1. 将计算结果缓存,避免重复计算
  2. 使用cache缓存存答案,key就是参数,value就是答案

例题

  • leedCode 509 斐波那契数列
    • //解法1:普通递归写法
      class Solution {
          public int fib(int n) {
              if(n == 0){
                  return 0;
              }
              if( n == 1){
                  return 1;
              }
              return fib(n-1) + fib(n-2);
          }
      }
      
      //解法2:通过缓存减少重复计算
      class Solution {
          Map<Integer,Integer> cache=new HashMap<>();
          public int fib(int n) {
              if(cache.get(n) != null){
                  return cache.get(n);
              }
              if(n == 0){
                  return 0;
              }
              if( n == 1){
                  return 1;
              }
              int ans = fib(n-1) + fib(n-2);
              cache.put(n,ans);
              return ans;
          }
      }
      
      //解法3:通过迭代替换递归
      //类似双指针,pre,next每次都从左往右移动,没移动一次就做一次计算下一个数的动作。边界是n<2
      class Solution {
          public int fib(int n) {
              if( n < 2){
                  return n;
              }
              int pre = 0,next = 0,ans = 1;
              for(int i = 2 ;i<=n ; i++){
                  pre = next;
                  next = ans;
                  ans = pre + next;
              }
              return ans;
          }
      }

    • 70. 爬楼梯 (青蛙跳台阶)
      • //直接用户递归求解会超时,必须用cache缓存所有答案
        class Solution {
            Map<Integer,Integer> cache=new HashMap<>();
            public int climbStairs(int n) {
                if(cache.get(n) != null){
                    return cache.get(n);
                }
                if( n == 0 ){
                    return 1;
                }
        
                if( n == 1 ){
                    return 1;
                }
                
                if( n == 2 ){
                    return 2;
                }
                
                int ans = climbStairs(n-1) + climbStairs(n-2);
                cache.put(n,ans);
                return ans;
            }
        }

  • //动态规划求解,没看懂
    class Solution {
        public int climbStairs(int n) {
            int a = 1, b = 1, sum;
            for(int i = 0; i < n - 1; i++){
                sum = a + b;
                a = b;
                b = sum;
            }
            return b;
        }
    }
    

2、分治

  1. 将一个大问题拆分成小问题,各个击破,然后将小问题的解组合起来
  2. 几乎等价标准的递归,唯一的区别就是将小问题的解组合起来

例题

  • leedCode 98

3、回溯

  1. 找到所有满足某些条件的结果,不断试错,知错就改(并且问题可以用递归实现)
  2. 类似暴力搜索,但是比暴力搜索更高效(因为知错就改)

例题

  •     leedCode 22

三、递归形式的分类

直接递归(Direct Recursion)

在直接递归中,函数在其定义中直接调用自身。这是最基本和常见的形式

// 计算阶乘的直接递归示例
public class Main {
    public static int factorial(int n) {
        if (n == 0) {
            return 1;
        } else {
            return n * factorial(n - 1);
        }
    }

    public static void main(String[] args) {
        int result = factorial(5);
        System.out.println("Factorial of 5 is: " + result);
    }
}

间接递归(Indirect Recursion)

 在间接递归中,函数不直接调用自身,而是通过调用其他函数间接地调用自身。这种形式下,可能形成一个递归调用链。

// 间接递归示例:偶数和奇数的判断
public class Main {
    public static boolean isEven(int n) {
        if (n == 0) {
            return true;
        } else {
            return isOdd(n - 1);
        }
    }

    public static boolean isOdd(int n) {
        if (n == 0) {
            return false;
        } else {
            return isEven(n - 1);
        }
    }

    public static void main(String[] args) {
        System.out.println("Is 6 even? " + isEven(6));
        System.out.println("Is 7 odd? " + isOdd(7));
    }
}

尾递归(Tail Recursion)

 尾递归是指递归函数中递归调用是函数的最后一个操作。在一些编程语言和编译器中,尾递归调用可以被优化为迭代形式,从而节省内存空间。

// 尾递归示例:计算斐波那契数列
public class Main {
    public static int fibonacci(int n, int a, int b) {
        if (n == 0) {
            return a;
        } else {
            return fibonacci(n - 1, b, a + b);
        }
    }

    public static void main(String[] args) {
        int result = fibonacci(6, 0, 1);
        System.out.println("Fibonacci of 6 is: " + result);
    }
}
// 尾递归的迭代形式示例:计算斐波那契数列
public class Main {
    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        
        int a = 0;
        int b = 1;
        int temp;
        
        for (int i = 2; i <= n; i++) {
            temp = b;
            b = a + b;
            a = temp;
        }
        
        return b;
    }

    public static void main(String[] args) {
        int result = fibonacci(6);
        System.out.println("Fibonacci of 6 is: " + result);
    }
}

多态递归(Polymorphic Recursion)

 多态递归是指函数在递归调用时采用不同的参数类型,导致函数的行为因输入数据类型的不同而不同。这种形式通常用于处理具有不同结构或数据类型的问题。

// 多态递归示例:根据不同输入类型处理列表
import java.util.List;

public class Main {
    public static void processList(Object obj) {
        if (obj instanceof List) {
            List<?> list = (List<?>) obj;
            for (Object item : list) {
                processList(item);
            }
        } else {
            System.out.println(obj);
        }
    }

    public static void main(String[] args) {
        List<Object> nestedList = List.of(1, List.of(2, 3), 4);
        processList(nestedList);
    }
}

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

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

相关文章

基于Spark中随机森林模型的天气预测系统

基于Spark中随机森林模型的天气预测系统 在这篇文章中&#xff0c;我们将探讨如何使用Apache Spark和随机森林算法来构建一个天气预测系统。该系统将利用历史天气数据&#xff0c;通过机器学习模型预测未来的天气情况&#xff0c;特别是针对是否下雨的二元分类问题。 简介 Ap…

SpringBoot3整合RabbitMQ之四_发布订阅模型中的fanout模型

SpringBoot3整合RabbitMQ之四_发布订阅模型中的fanout模型 文章目录 SpringBoot3整合RabbitMQ之四_发布订阅模型中的fanout模型3. 发布/订阅模型之fanout模型1. 说明1. 消息发布者1. 创建工作队列的配置类2. 发布消费Controller 2. 消息消费者One3. 消息消费者Two4. 消息消费者…

实际项目中如何使用Git做分支管理

前言 Git是一种强大的分布式版本控制系统&#xff0c;在实际项目开发中使用Git进行分支管理是非常常见的做法&#xff0c;因为它可以帮助团队高效的协作和管理项目的不同版本&#xff0c;今天我们来讲讲在实际项目中最常用的Git分支管理策略Git Flow。 常见的Git分支管理策略…

IDEA2024.1版本震撼来袭,手把手教你激活!

前言 作为一个Java程序猿&#xff0c;必不可少的一款开发IDE神器&#xff1a;IntelliJ IDEA&#xff0c;简称“IDEA”。就在前天&#xff08;2024.4.4&#xff09;终于推出了心心念念的2024.1版本。 IntelliJ IDEA 2024.1 引入了一系列令人期待的升级&#xff0c;可以帮助您简…

Nuxt 3 项目中配置 Tailwind CSS

官方文档&#xff1a;https://www.tailwindcss.cn/docs/guides/nuxtjs#standard 安装 Tailwind CSS 及其相关依赖 执行如下命令&#xff0c;在 Nuxt 项目中安装 Tailwind CSS 及其相关依赖 npm install -D tailwindcss postcss autoprefixerpnpm install -D tailwindcss post…

深度剖析扫雷游戏的各个知识点(1)

哈喽&#xff0c;小伙伴&#xff0c;大家好&#xff0c;今天我来水一篇文章。害&#xff0c;也不算真的水吧&#xff0c;这次带大家深度剖析初次写扫雷游戏程序时还未接触到的知识点。废话不多说&#xff0c;直接进入正题 不知小伙伴们是否还记得当时我说过扫雷游戏我们是以多个…

AIGC实战——ProGAN(Progressive Growing Generative Adversarial Network)

AIGC实战——ProGAN 0. 前言1. ProGAN2. 渐进式训练3. 其他技术3.1 小批标准差3.2 均等学习率3.3 逐像素归一化 4. 图像生成小结系列链接 0. 前言 我们已经学习了使用生成对抗网络 (Generative Adversarial Network, GAN) 解决各种图像生成任务。GAN 的模型架构和训练过程具有…

2023 年网络安全热点技术发展态势

文章目录 前言一、人工智能信息技术迎来井喷式发展期二、零信任网络安全架构即将投入实际部署三、美国全面推动军政业务向云环境迁移四、专用太空软硬件与独立卫星网络并行发展五、量子信息技术与网络安全领域加速融合前言 在 2023 年取得进展的信息技术不在少数。从网络安全的…

从300亿分子中筛出6款,结构新且易合成,斯坦福抗生素设计AI模型登Nature子刊

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 全球每年有近 500 万人死于抗生素耐药性&#xff0c;因此迫切需要新的方法来对抗耐药菌株。 …

HTML5.Canvas简介

1. Canvas.getContext getContext(“2d”)是Canvas元素的方法&#xff0c;用于获取一个用于绘制2D图形的绘图上下文对象。在给定的代码中&#xff0c;首先通过getElementById方法获取id为"myCanvas"的Canvas元素&#xff0c;然后使用getContext(“2d”)方法获取该Ca…

音视频开发之旅(83)- 腾讯音乐开源高质量唇形同步模型--MuseTalk

目录 1.效果展示 2.原理学习 3.流程分析 4.资料 一、效果展示 -- &#xff08;推理素材来源于网络&#xff0c;如有侵权&#xff0c;联系立删&#xff01;&#xff09; 唱歌效果&#xff08;歌曲有suno生成&#xff09; 用于推理的视频素材来源于网络&#xff0c;如有侵权&…

Java中常见的排序算法

常见算法可以分为两大类&#xff1a;   非线性时间比较类排序&#xff1a;通过比较来决定元素间的相对次序&#xff0c;由于其时间复杂度不能突破O(nlogn)&#xff0c;因此称为非线性时间比较类排序。   线性时间非比较类排序&#xff1a;不通过比较来决定元素间的相对次序…

Windows应急响应

1.排查隐藏账号 查看注册表 找到攻击者用户目录文件 排查用户异常 eventvwr.msc 分析用户登录日志 排查可疑端口 排查可疑进程 检查启动项、计划任务和服务 查看系统补丁信息 安装火绒&#xff0c;在安全工具里有火绒剑 计划任务 使用D盾对主机进行检测&#xff0c;发现隐藏账户…

python自定义库的打包和安装

要将自定义库安装到python的三方包地址site-packages中&#xff0c;除了可以直接的复制之外&#xff0c;更为合理科学的方法是通过build和install的方式进行。因为直接复制仅仅作为一种临时的简单的方法&#xff0c;而且只能针对源码进行&#xff0c;也不好进行科学管理&#x…

AJAX —— 学习(三)(完结)

目录 一、jQuery 中的 AJAX &#xff08;一&#xff09;get 方法 1.语法介绍 2.结果实现 &#xff08;二&#xff09;post 方法 1.语法介绍 2.结果实现 &#xff08;三&#xff09;通用型的 AJAX 方法 1.语法介绍 2.结果实现 二、AJAX 工具库 axios &#xff08…

简历复印--原型模式

1.1 夸张的简历 简历的打印。"对编程来说&#xff0c;简单的复制粘贴极有可能造成重复代码的灾难。我所说的意思你根本还没听懂。那就以刚才的例子&#xff0c;我出个需求你写写看&#xff0c;要求有一个简历类&#xff0c;必须要有姓名&#xff0c;可以设置性别和年龄&am…

第十四届蓝桥杯省赛大学C组(C/C++)填充

原题链接&#xff1a;填充 有一个长度为 n 的 01 串&#xff0c;其中有一些位置标记为 ?&#xff0c;这些位置上可以任意填充 0 或者 1&#xff0c;请问如何填充这些位置使得这个 01 串中出现互不重叠的 0 和 1 子串最多&#xff0c;输出子串个数。 输入格式 输入一行包含一…

SQLite 4.9的 OS 接口或“VFS”(十三)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite字节码引擎&#xff08;十二&#xff09; 下一篇:SQLite 4.9的虚拟表机制(十四) 1. 引言 本文介绍了 SQLite OS 可移植性层或“VFS” - 模块位于 SQLite 实现堆栈底部 提供跨操作系统的可移植性。 VFS是Virtual File…

5560.树的直径

蛮不错的一道题目&#xff0c;你要利用树的性质分析出&#xff0c;你只需要维护上一次的树的直径的两个端点就好了 #include<iostream>using namespace std; using ll long long; using pii pair<int,int>; const int N 6e510; const int inf 0x3f3f3f3f; cons…

算法:树形dp(树状dp)

文章目录 一、树形DP的概念1.基本概念2.解题步骤3.树形DP数据结构 二、典型例题1.LeetCode&#xff1a;337. 打家劫舍 III1.1、定义状态转移方程1.2、参考代码 2.ACWing&#xff1a;285. 没有上司的舞会1.1、定义状态转移方程1.2、拓扑排序参考代码1.3、dfs后序遍历参考代码 一…