算法系列--递归

一.如何理解递归

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

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

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

  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.mzph.cn/news/760721.shtml

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

相关文章

C语言例3-39:赋值时类型转换可能出现错误的例子

进行数据类型转换时&#xff0c;需要注意以下几点&#xff1a; 强制类型转换获得的是一个所需类型的中间量&#xff0c;原来表达式的类型并不发生变化。例如(double)a只是将变量a的值转换成一个double型的中间量&#xff0c;但其数据类型并未转换为double型表达式计算过程中&a…

Java开发---上海得帆(一面)

面试感受 这是我的第一次面试&#xff0c;我感觉我这次面试的很差&#xff0c;很糟糕&#xff0c;十分的糟糕&#xff0c;万分的糟糕。第一次面试&#xff0c;面试了半个小时。我去真的好紧张&#xff0c;脑子里一篇空白。脑子空白还不是最惨的&#xff0c;最惨的是那个八股文…

游戏客户端开发

1、LOL里面用到的是什么同步机制&#xff1f; 2、网络不好的情况下人物会出现瞬移等情况&#xff0c;怎样避免&#xff1f; 3、游戏里面有没有涉及数据存储&#xff0c;如存档之类的&#xff1f;、 4、如果让你设计存档&#xff0c;会如何着手&#xff1f; 5、以二进制方式…

反光衣AI检测识别算法---豌豆云

工服反光衣穿戴AI检测识别算法是一项基于人工智能视觉智能分析的创新技术。 它通过使用现场摄像头对工地进行全天候、不间断的监测&#xff0c;旨在提高工地安全管理水平。 这个系统的核心功能是自动检测和识别潜在的危险行为&#xff0c;例如未穿戴工服、反光衣、安全带或未…

聊一聊基础

基础 1、面向对象编程是什么&#xff1f; 面向对象编程在解决问题的时候&#xff0c;会先抽象出对象&#xff0c;再使用对象去解决问题。 面向过程把解决问题的过程拆成一个个方法&#xff0c;通过一个个方法的执行解决问题。 面向对象编程有三大特性&#xff0c;继承、封装…

containerd管理命令ctr常用操作 —— 筑梦之路

Containerd ctr、crictl、nerdctl客户端命令——筑梦之路_crictl login-CSDN博客 镜像常用操作 1. 拉取镜像 ctr images pull docker.io/library/nginx:alpine 注意&#xff1a;containerd支持oci标准的镜像&#xff0c;所以可以直接使用docker官方或dockerfile构建的镜像 需…

RabbitMQ--04--Spring Cloud Stream(消息驱动)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.Spring Cloud Stream1. 基本介绍https://spring.io/projects/spring-cloud-stream#overview 2.Spring Cloud Stream 解决的痛点问题3.设计思想Stream为什么可以统…

2024网络安全-自学笔记

前言 一、什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防…

新火种AI|国产手机抢滩“AI+折叠屏”赛道,行业洗牌大战就此开启?

作者&#xff1a;小岩 编辑&#xff1a;彩云 从2023年到2024年&#xff0c;随着新一波人工智能浪潮的加速&#xff0c;消费电子产品也迎来了全新的话题——AI。更重要的是&#xff0c;这场战争看似没有硝烟&#xff0c;但各大厂商都已经暗自角力了许久&#xff0c;特别是手机…

Java二阶知识点总结(八)Linux和Docker

Linux 1、常用命令&#xff1a; cat&#xff1a;查看文件内容cd&#xff1a;切换目录ifconfig或ip addr&#xff1a;用于查看网络接口的地址和参数pwd&#xff1a;显示当前目录的绝对路径ls/ll&#xff1a;查看当前目录下的所有文件touch&#xff1a;创建文件mkdir&#xff1…

Windows 11 鼠标右键可选择 cmd 命令行选项

** Windows 11 鼠标右键可选择 cmd 命令行选项 ** 在文件夹内打开命令行&#xff0c;只能使用 Windows 自带的 PowerShell &#xff0c; 作为一个 cmd 重度使用用户来说很是折磨&#xff0c;需要打开 cmd 然后切换盘符再 cd 。。。 现在咱们自己创建一个可以打开 cmd 的方法…

Qt调用内置图标

int IconIndex0; QIcon icon QApplication::style()->standardIcon((QStyle::StandardPixmap)IconIndex);按以上代码可以调用Qt内置的71个图标&#xff0c;只要变换IconIndex就可以了&#xff0c;IconIndex为[0,70]。显示如下&#xff1a;图标index名称。

图论中的最小生成树:Kruskal与Prim算法深入解析

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;アンビバレント—Uru 0:24━━━━━━️&#x1f49f;──────── 4:02 &#x1f504; ◀️ ⏸ ▶️ ☰ …

游戏客户端-面经

做一道题&#xff1a;一副牌&#xff0c;能不能全凑成顺子和同花对C是什么级别的认知。内联函数可不可以是虚函数New和malloc有什么区别多态有几种静态多态是什么&#xff0c;动态多态是什么&#xff1f;什么是拷贝构造函数什么情况下要自己写拷贝构造函数什么是移动构造函数深…

Meta分析:如何为生态环境领域提供可靠结论

Meta分析&#xff0c;又称元分析&#xff0c;是一种统计方法&#xff0c;用于整合多个独立研究的结果&#xff0c;从而得出更为全面、可靠的结论。在生态领域&#xff0c;Meta分析发挥着越来越重要的作用&#xff0c;它有助于解决单个研究样本量小、结果不一致等问题&#xff0…

西井科技与安通控股签署战略合作协议 共创大物流全新生态

2024年3月21日&#xff0c;西井科技与安通控股在“上海硅巷”新象限空间正式签署战略合作框架协议。双方基于此前在集装箱物流的成功实践与资源优势&#xff0c;积极拓展在AI数字化产品、新能源自动驾驶解决方案和多场景应用&#xff0c;以及绿色物流链等领域的深度探索、强强联…

洛克王国卡小游戏2

kaijiang1.setBackground(Color.WHITE);/*去除按钮背景kaijiang1.setContentAreaFilled(false);*///添加到界面getContentPane().add(kaijiang1);}private void extracted1() {JLabel beijin new JLabel(new ImageIcon("D:\\bc2\\kaixinge\\wendang\\2266.png"));be…

视频号下载助手失效了?如何解决下载视频问题!

在刷短视频的时候难免会遇到部分的视频号视频下载不下来&#xff0c;那我们该如何解决视频号下载问题呢&#xff1f; 视频号下载助手解决方案 视频号下载助手失效分为两种情况! 1、可以解析&#xff0c;但不能下载 根据使用视频号下载助手常见的问题&#xff0c;我们发现会有…

MATLAB/Simulink 学习路径

chhttty个人博客总目录 参见

Linux本地部署TeslaMate结合内网穿透实现公网访问内网车辆信息

文章目录 1. Docker部署TeslaMate2. 本地访问TeslaMate3. Linux安装Cpolar4. 配置TeslaMate公网地址5. 远程访问TeslaMate6. 固定TeslaMate公网地址7. 固定地址访问TeslaMate TeslaMate是一个开源软件&#xff0c;可以通过连接特斯拉账号&#xff0c;记录行驶历史&#xff0c;统…