算法系列--递归

news2024/9/26 3:29:35

一.如何理解递归

递归对于初学者来说是一个非常抽象的概念,笔者在第一次学习时也是迷迷糊糊的(二叉树遍历),递归的代码看起来非常的简洁,优美,但是如何想出来递归的思路或者为什么能用递归这是初学者很难分析出来的

笔者在学习的过程中通过刷题,也总结出自己的一些经验,总结来说就是要胆大心细,宏观看待问题

其实很多递归的问题如果从宏观的角度去看,其实特别简单,比如二叉树的后序遍历,他无非就是:

  1. 你先给我一个根节点
  2. 访问根节点的左子树
  3. 访问根节点的右子树
  4. 再打印当前节点的值

对于每一个节点的操作都是相同的,如果从宏观的角度看,我们可以把一个复杂的二叉树想象成一个只有三个节点的二叉树
在这里插入图片描述
把二叉树的后序遍历就当做访问这个只有三个节点的二叉树,按照左右根的顺序遍历

dfs(TreeNode root) {
	if(root == null) return;
	
	dfs(root.left);// 访问左节点
	dfs(root.right);// 访问右结点
	println(root.val);// 打印当前节点的值
}

大致总结下来递归问题的思路如下:

  1. 分析:根据题目分析,判断是否有重复的子问题,如果有,就可以利用递归解决,设计出函数头,从宏观的角度想,要完成这次操作,这个"接口"需要什么参数(二叉树的遍历需要root,快排需要一个数组和开始结束位置)
  2. 设计函数体:只关注某一个子问题的具体操作,比如二叉树的后序遍历的子问题就完成三步:访问左子树,访问右子树,打印当前节点
  3. 递归出口:确定好递归出口,将子问题分割到最小单元进行确定,比如二叉树的遍历当节点为空时就不需要再去执行任何操作了,直接返回即可,快排,分割到数组只有一个数字或者为空时(l >= r)就不需要继续分治了

二.例题解析:

1.汉诺塔问题

链接:https://leetcode.cn/problems/hanota-lcci/description/

分析:

  1. 函数头:给我三个柱子和盘子数
  2. 函数体:先借助c将a上的n-1个盘子移动到b,然后将a剩余的最大的盘子移动到c,再借助a,将b上的n-1个盘子移动到c
  3. 递归出口:当只有一个盘子的时候,直接移动
    在这里插入图片描述

代码:

class Solution {
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
        int n = A.size();
        dfs(A,B,C,n);
    }

    private void dfs(List<Integer> a, List<Integer> b, List<Integer> c,int n) {
        // 递归结束条件 只有一个盘子的时候直接移动
        if(n == 1) {
            c.add(a.remove(a.size() - 1));
            return;
        }

        // 模拟:借助c,将a上的n-1个盘子移动到b上
        dfs(a,c,b,n-1);
        // 将最大的盘子移动到c上
        c.add(a.remove(a.size() - 1));
        // 模拟:借助a,将b盘上的n-1个盘子移动到c上
        dfs(b,a,c,n-1);
    }
}

2.合并两个有序链表

链接: https://leetcode.cn/problems/merge-two-sorted-lists/

分析:

  1. 函数头:两个链表的头结点
  2. 函数体:判断较小值,合并之后的所有节点,并连接返回的节点
  3. 递归出口:只有一个节点或者为空
    在这里插入图片描述

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // 递归
        if(list1 == null) return list2;
        if(list2 == null) return list1;

        // 将后面的链表给我合并好,并且返回合并好的节点
        if(list1.val < list2.val) {
            list1.next = mergeTwoLists(list1.next,list2);
            return list1;
        }else {
            list2.next = mergeTwoLists(list2.next,list1);
            return list2;
        }
    }
}

3.反转链表

链接: https://leetcode.cn/problems/reverse-linked-list/submissions/514361305/

分析:

  1. 函数头:给我头结点,逆序整个链表
  2. 函数体:逆序之后的所有节点,并且返回逆序之后的头结点,然后和当前节点拼接
  3. 递归出口:只有一个节点或者为空
    在这里插入图片描述

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {

        // 递归出口
        if(head == null || head.next == null) return head;

        // 函数体  你给我逆置后面的所有链表并且返回新的头结点
        ListNode newhead = reverseList(head.next);

        // 反转
        head.next.next = head;
        head.next = null;

        return newhead;
    }
}

4.两两交换链表中的节点

链接: https://leetcode.cn/problems/swap-nodes-in-pairs/

分析:

  1. 函数头:重复子问题就是`给我一个节点,两两交换后面的链表的所有节点
  2. 函数体:关注每一个子问题要干什么,得到交换后的头节点,然后链接这个头结点
  3. 递归出口:空或者只有一个节点
    在这里插入图片描述

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {

        if(head == null || head.next == null) return head;
        ListNode ret = head.next;// 最终要返回的节点应该是head.next(是头结点的下一个节点)

        ListNode newHead = swapPairs(head.next.next);

        head.next.next = head;
        head.next = newHead;

        return ret;

    }
}

5.Pow(x, n)- 快速幂

链接: https://leetcode.cn/problems/powx-n/submissions/514390268/

分析:

  1. 函数头:结合快速幂的思想,递归函数就是求x ^ n的值
  2. 函数体:每一个子问题的操作,得到 x ^ n / 2的值,再判断返回的结果的值
  3. 递归出口:n == 0

在这里插入图片描述
代码:

class Solution {
    public double myPow(double x, int n) {
        // 注意n可能为负数
        return n < 0 ? 1.0 / pow(x,-n) : pow(x,n);
    }

    public double pow(double x,int n) {
        if(n == 0) return 1.0;
        double tmp = pow(x,n/2);
        return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
    }
}

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

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

相关文章

[数据集][目标检测]高质量铁路轨道缺陷检测数据集VOC+YOLO格式1050张6类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1050 标注数量(xml文件个数)&#xff1a;1050 标注数量(txt文件个数)&#xff1a;1050 标注…

Altair CFD™ 无比宽广的 CFD 仿真解决方案范围

Altair CFD 提供了一套全面的工具来解决流体力学问题。无论您是要对建筑物进行热分析、预测车辆空气动力学、优化齿轮箱加油、降低冷却风扇噪音还是开发创新医疗设备&#xff0c;Altair CFD 都可以提供帮助。 提供多种方法&#xff0c;包括&#xff1a; 用于热和通用应用的通…

公职人员上班时间看股票,该不该上纲上线?

公职人员炒股是一个复杂的问题&#xff0c;需要综合考虑多方面的因素。首先&#xff0c;炒股作为一种个人投资行为&#xff0c;本身并不违法&#xff0c;但在特定情况下&#xff0c;公职人员参与股市投资可能会引发一些问题和争议。 对于公职人员炒股&#xff0c;关键是要确保其…

vue@2.7.16 使用less、less-loader

遇到问题&#xff0c;npm install less-loader7.3.0 --save安装好less-loader后&#xff0c;执行npm run serve 项目运行不起来&#xff0c;排查后发现在安装less-loader后就提示需要安装less&#xff0c;正确的安装应如下&#xff1a; npm install less less-loader7.3.0 --sa…

docker实践教程,mysql中使用自定义目录实现数据挂载(二)

有一些知识点在docker实践教程&#xff0c;nginx中使用数据卷映射修改前端网页&#xff08;一&#xff09;&#xff0c;就不累述了。 下载mysql的镜像 docker pull mysql创建容器 先去Docker Hub看看mysql是怎么使用的 可知&#xff0c;运行命令为&#xff1a;&#xff08;…

vue-admin-template极简的 vue admin 管理后台的动态路由实现方法

项目源码地址&#xff1a;GitHub - PanJiaChen/vue-admin-template: a vue2.0 minimal admin template 注意&#xff1a;项目中的路由均写在 src\router\index.js 中&#xff0c;其中默认包含 constantRoutes 数组&#xff0c;这是固定路由&#xff0c;无论用户是什么角色&…

数据结构从入门到精通——冒泡排序

冒泡排序 前言一、冒泡排序的基本思想二、冒泡排序的特性总结三、冒泡排序的动画演示四、冒泡排序的具体代码test.c 前言 冒泡排序是一种简单的排序算法&#xff0c;通过重复遍历待排序数列&#xff0c;比较相邻元素的大小并交换位置&#xff0c;使得每一轮遍历后最大&#xf…

ubuntu内存不足,用Swap扩展增加虚拟内存

Linux增大Swap分区&#xff0c;可以增加虚拟内存&#xff0c;以解决电脑卡机&#xff0c;内存不足等问题 top可以查看cpu的使用情况 lscpu可以查看本机配置的cpu硬件情况 查看内存使用情况 free -h (下面显示"交换"或者Swap等字样说明系统已经启动了Swap&#xff…

EMC Unity存储系统(包含VNXe)常用检查命令

DELL EMC的Unity存储系统&#xff0c;包括VNXe存储系统的OS已经完全和Clariion 的VNX不同了&#xff0c;近期遇到很多关于EMC unity存储系统故障的一些初步检查需求&#xff0c;下面是一些对于DELL EMC Unity存储系统的最常用的底层检查命令&#xff0c;可以对系统故障有个初步…

深度学习——线性代数相关知识

线性代数基础知识 一、线性代数基础知识1、标量2、向量3、矩阵4、张量5、点积6、向量—矩阵积7、矩阵—矩阵乘法 二、小结 一、线性代数基础知识 本节将介绍简要地回顾一下部分基本线性代数内容&#xff0c;线性代数中的基本数学对象、算术和运算&#xff0c;并用数学符号和相…

Linux编程4.11 网络编程-广播

广播实现一对多的通讯 它通过向广播地址发送数据报文实现的 1、套接字选项 套接字选项用于修饰套接字以及其底层通讯协议的各种行为。函数setsockopt和getsockopt可以查看和设置套接字的各种选项。 #include <sys/types.h> #include <sys/socket.h>int getso…

申请免费IP地址证书

目录 IP申请SSL证书需要满足什么条件呢&#xff1f; 为什么需要申请IP地址证书&#xff1f; 支持IP地址SSL证书类型 DV级别IP SSL证书和OV级别IP SSL证书的区别 申请公网IP地址证书有免费的吗&#xff1f; 背景&#xff1a;当用户直接通过IP地址而非域名访问网站时&#xf…

后端如何返回404地址

当我们网站输入不存在的地址&#xff0c;经常会出现404的页面&#xff0c;这是如何做到的 1.添加配置 spring:mvc:view:prefix: /templates/suffix: .html 2.resources下添加templates目录&#xff0c;下面放404的网站 3.添加依赖&#xff0c;版本在主pom里面配置好了&#x…

霍格沃兹测试开发从人员外包到测试工具、测试平台,提供全方位的测试解决方案~

随着学社的学员越来越多&#xff0c;影响力越来越大&#xff0c;不停有学员和企业问我们&#xff1a;能否提供人员外包服务&#xff1f;与此同时&#xff0c;企业对于外包人员的业务技能要求也越来越高&#xff0c;寻找一个稳定靠谱的供应商也成了很多学员所在公司的需求。对此…

web前端常用标签(html)

1.定义 1.1标签 语法规范&#xff1a;<标签名 属性名"属性值">标签名</标签名> 标签之间可以嵌套 1.2属性 定制元素的行为的。属性是不通用的&#xff0c;每一个标签存在自身的属性。当属性名属性值时&#xff0c;可以只写属性值 2.HTML常用标签 2…

【人工智能Ⅱ】实验2:VGG图像分类

实验2&#xff1a;VGG图像分类 一&#xff1a;实验目的与要求 1&#xff1a;掌握VGG网络的原理与结构。 2&#xff1a;学会利用VGG网络建立训练模型&#xff0c;并对模型进行评估。 3&#xff1a;学会使用VGG网络进行分类。 二&#xff1a;实验内容 1&#xff1a;用VGG网络…

扩展欧拉定理

为了求a^bmodm的余数,我们可以利用扩展欧拉定理给出的同余方程,转化成一个好求的式子,首先我们要能够解出欧拉函数.欧拉函数讲解可以看看这篇欧拉函数最全总结-CSDN博客(原理我不懂,只会用) 下面给出代码 using i64 long long; int phi(int n) {int res n;for (int i 2; i…

【C语言】内存管理内存管理函数文件管理文件管理函数

主页&#xff1a;醋溜马桶圈-CSDN博客 专栏&#xff1a;C语言_醋溜马桶圈的博客-CSDN博客 gitee&#xff1a;mnxcc (mnxcc) - Gitee.com 目录 1.C/C程序的内存开辟 2.内存相关的函数 2.1 memcpy 2.1.1 memcpy函数的使用 2.1.2 memcpy函数的模拟实现 2.2 memmove 2.2.2 me…

四阶Runge-Kutta方法求解高阶微分方程

一、经典的Runge-Kutta方法&#xff08;四级四阶RK方法&#xff09; Runge-Kutta法&#xff08;简写为RK方法&#xff09;既可达到较高精度&#xff0c;又可避免高阶导数计算。 对微分方程,在区间上的四阶Runge-Kutta方法的公式如下&#xff1a; 二、利用4阶Runge-Kutta方法计…

Elasticsearch - Docker安装Elasticsearch8.12.2

前言 最近在学习 ES&#xff0c;所以需要在服务器上装一个单节点的 ES 服务器环境&#xff1a;centos 7.9 安装 下载镜像 目前最新版本是 8.12.2 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.2创建配置 新增配置文件 elasticsearch.yml http.host…