当前位置: 首页 > news >正文

【Java算法】递归

 🔥个人主页: 中草药 

 🔥专栏:【算法工作坊】算法实战揭秘


 🍇一.递归

概念

递归是一种解决问题的方法,其中函数通过调用自身来求解问题。这种方法的关键在于识别问题是否可以被分解为若干个相似但规模更小的子问题。递归函数有两个主要组成部分:

  1. 基本情况(Base Case):这是递归调用的终止条件。每个递归函数都必须有一个或多个明确的基本情况,否则递归将无限进行下去。
  2. 递归步骤(Recursive Step):这是函数调用自身的部分。在此步骤中,问题被分解为更小的子问题,然后递归地求解这些子问题。

递归的本质可以理解为 可以把一个主问题拆分成若干个相同的子问题

宏观的理解递归

        递归其实是比较抽象的一种算法,完全熟练的运用它,需要时间的积累与深入的理解,因此我们可以学会宏观的去看待递归,帮助我们去解决算法问题

1.不必过分关注递归的细节展开图

2.把递归的函数看做一个黑盒(不去深究)

3.相信这个黑盒一定能完成这个任务

用法 

如何写好一个递归

  1. 先找到相同的子问题--->函数头的设计
  2. 只关心某一个子问题是如何解决的--->函数体的书写
  3. 注意一下递归函数的出口

应用场景

递归非常适合处理以下类型的问题:

  • 分治法:问题可以被分解为独立且较小的子问题。
  • 树形结构:例如文件系统的目录树、DOM树等。
  • 回溯算法:如八皇后问题、迷宫寻路等。

 🍈二. 面试题 08.06. 汉诺塔问题

题目链接:面试题 08.06. 汉诺塔问题

代码

public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {dfs(A,B,C,A.size());return;}public void dfs(List<Integer> A, List<Integer> B, List<Integer> C,int n){//算法的出口if(n==1){C.add(A.remove(A.size()-1));return;}dfs(A, C, B, n-1);C.add(A.remove(A.size()-1));dfs(B, A, C, n-1);}

算法原理 

汉诺塔问题是递归问题的一个经典问题,和常规问题一样,拆分成细小的步骤

汉诺塔问题通常有三个柱子A、B、C,以及n个不同大小的圆盘,初始时所有的圆盘都堆叠在柱子A上,要求将它们全部移动到柱子C上,但在移动过程中必须遵守以下规则:

  1. 每次只能移动一个圆盘。
  2. 在任何时刻,一个较大圆盘都不能放在较小圆盘上面

代码详解

  • hanota 方法是主入口点,它接受三个列表作为参数,分别代表三个柱子A、B、C。
  • dfs 方法是一个递归函数,它接受四个参数:柱子A、B、C以及当前要移动的圆盘数量n。
  • n == 1时,这是递归的基本情况,直接将A上的最后一个圆盘移动到C。
  • 对于n > 1的情况,首先递归地将n-1个圆盘从A借助B移动到C;然后将A上的最后一个圆盘直接移动到C;最后再递归地将n-1个圆盘从B借助A移动到C。

🍉 三. 21.合并两个有序链表

题目链接:21.合并两个有序链表

代码

public ListNode mergeTwoLists(ListNode list1, ListNode list2) {//不能用elseif(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(list1,list2.next);return list2;}}

算法原理

  1. 特殊情况处理:首先检查输入的两个链表list1list2是否为空。
    • 如果list1为空,则直接返回list2
    • 如果list2为空,则直接返回list1
  2. 递归合并:如果两个链表都不为空,则比较当前节点的值。
    • 如果list1的当前节点值小于等于list2的当前节点值,那么将list1next指向list1.nextlist2的合并结果,并返回list1
    • 否则,将list2next指向list1list2.next的合并结果,并返回list2

这段代码使用了递归的方式来合并两个有序链表。其基本思想是:

  • 基本情况:如果其中一个链表为空,那么合并的结果就是另一个链表。
  • 递归步骤:如果两个链表都不为空,则比较当前节点的值。
    • 如果list1的当前节点值小于等于list2的当前节点值,那么list1将成为合并后链表的一部分,然后递归地去合并list1的下一个节点和list2
    • 如果list2的当前节点值小于list1的当前节点值,那么list2将成为合并后链表的一部分,然后递归地去合并list1list2的下一个节点。

🍊四. 206.反转链表

代码

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

算法原理

这里可以比较这道题的 迭代代码 加深理解

public ListNode reverseList1(ListNode head) {if(head==null){return head;}ListNode cur=head.next;head.next=null;while(cur!=null){ListNode curn=cur.next;cur.next=head;head=cur;cur=curn;}return head;}
  1. 基本情况:如果当前节点head为空或者当前节点是链表的最后一个节点(即head.next == null),那么直接返回head。这是因为如果链表为空或者只剩一个节点,就不需要反转了,直接返回即可。

  2. 递归步骤:如果当前节点不是最后一个节点,递归地反转head.next,即反转当前节点之后的所有节点。这里newHead将是反转后的新头节点,即原来链表的最后一个节点成为了新的头节点。 

  3. 链接反转:在递归调用返回后,将当前节点head连接到新头节点newHead后面。这一步是通过将head.next.next = head;来实现的,即将head插入到新反转链表的头部。

    • 注意,这里的head.next是原来链表中的下一个节点,现在它已经是反转链表的头节点了,所以我们通过head.next.next来访问原来链表的下下个节点,现在变成了反转链表的第二个节点。
  4. 断开连接:将headnext设为null,这样原来的链表就被切断了,从而完成了反转。

🍋五.  24.两两交换链表中的节点

题目链接:24.两两交换链表中的节点

代码

 public ListNode swapPairs(ListNode head) {if(head==null||head.next==null){return head;}ListNode tmp=swapPairs(head.next.next);ListNode ret=head.next;ret.next=head;head.next=tmp;return ret;}

算法原理

此代码,建议先用一个小链表模拟实现以下该过程,帮助理解这个递归

基本情况:如果当前节点head为空或head.next为空(即链表为空或只有一个节点),则直接返回head。这是因为单个节点或空链表无需交换。

递归步骤

  • 首先递归地调用swapPairs(head.next.next),这意味着我们假设head.next.next之后的部分已经被正确地交换好了。递归的目的是处理当前节点之后的所有节点。
  • tmp变量存储了从head.next.next开始的交换好的链表部分。
  • ret变量存储了head.next,即当前节点的下一个节点,它将成为新的头节点。
  • 接下来,将ret.next设置为head,这样就实现了headhead.next这两个节点的交换。
  • 最后,将head.next设置为tmp,这样就将剩余部分的链表正确地连接到了交换后的两个节点之后。

 🍌六.  50.Pow(x,n)

题目链接:50.Pow(x,n)

代码

public double myPow(double x, int n) {//存在负数情况,若为负数变为倒数return n<0?1/pow(x,-n):pow(x,n);}public double pow(double x,int n){if(n==0){return 1;//相当于x的0次方幂}double tmp=pow(x,n/2);//若为奇数,还需要在 * 上一个xreturn n%2==0?tmp*tmp:tmp*tmp*x;}

算法原理 

当拿到这道题,大多数人首先会想到循环,但问题是常规的这种循环会超时,因此我们应该将问题用递归的方式去简化,拆分成相同的子问题

这个算法采用了分治的思想,通过递归地将问题规模减半来快速计算幂。

  1. 基本情况:当n为0时,任何数的0次幂都是1。
  2. 递归步骤
    • 如果n是偶数,那么x^n可以表示为(x^(n/2))^2
    • 如果n是奇数,那么x^n可以表示为x * (x^(n-1))

通过递归地计算x^(n/2),我们可以将问题规模减半,从而大大减少了计算次数。这种方法的时间复杂度大约是O(log n),相比直接循环相乘的O(n)复杂度要高效得多。

 

相关文章:

【Java算法】递归

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 &#x1f347;一.递归 概念 递归是一种解决问题的方法&#xff0c;其中函数通过调用自身来求解问题。这种方法的关键在于识别问题是否可以被分解为若干个相似但规模更小…...

NIDS——suricata(三)

一、监控ICMP流量 1、ICMP流量特征 四大特征分别为&#xff1a;消息类型&#xff08;Type&#xff09;、代码&#xff08;Code&#xff09;、校验和&#xff08;Checksum&#xff09;、数据字段&#xff08;Data Field&#xff09;。这里我们使用 type消息类型。 ICMP 消息的类…...

运动耳机哪个牌子最好用?年度精选五款好用的骨传导耳机推荐

相信大家都已经深有体会&#xff0c;拿那种常规的入耳式无线蓝牙耳机来做运动耳机&#xff0c;很难满足运动需要。如果选择前两年流行的颈挂式无线运动蓝牙耳机&#xff0c;虽然简单轻巧&#xff0c;但也是入耳式设计&#xff0c;长时间佩戴耳朵不舒服。这样看来&#xff0c;运…...

鞋服企业信息化建设若干架构分享

鞋服企业的信息化建设有着自身的一些特点&#xff0c;这些特点主要体现在以下几个方面&#xff1a; 集成化&#xff1a;鞋服企业的信息化建设往往需要集成多种系统&#xff0c;如企业资源规划系统&#xff08;ERP&#xff09;、客户关系管理系统&#xff08;CRM&#xff09;、供…...

比较顺序3s1和3s2的搜索难度

在行列可自由变换的平面上&#xff0c;3点结构只有6个 (A,B)---6*30*2---(0,1)(1,0) 分类A和B&#xff0c;让A是6个3点结构&#xff0c;让B全是0。当收敛误差为7e-4&#xff0c;收敛199次取迭代次数平均值&#xff0c; 让训练集A-B矩阵的高分别是3&#xff0c;4&#xff0c;5…...

Vue3 el-switch @change事件在初始化时会自动调用问题

接收一个vue3项目&#xff0c;突然有一天&#xff0c;table里有个switch开关&#xff0c;请求数据之后就开始执行switch的change事件&#xff0c;我还啥都没操作&#xff0c;就报一推重复请求 <template><el-switch v-model"rec" inline-prompt :active-val…...

全面解析性能测试中的瓶颈分析与优化策略!

在软件开发的生命周期中&#xff0c;性能测试是确保应用程序在不同负载下稳定运行的关键步骤。性能瓶颈是导致系统性能下降的主要原因&#xff0c;及时发现并解决这些瓶颈&#xff0c;能够显著提升系统的响应速度和用户体验。本文将深入探讨性能测试中的瓶颈分析方法与优化策略…...

2018年Android面试题含答案--适合中高级(下)

熟悉Android系统的童鞋都知道&#xff0c;系统出于体验和性能上的考虑&#xff0c;app在退到后台时系统并不会真正的kill掉这个进程&#xff0c;而是将其缓存起来。打开的应用越多&#xff0c;后台缓存的进程也越多。在系统内存不足的情况下&#xff0c;系统开始依据自身的一套…...

基于SSM的汽车租赁系统+LW示例参考

系列文章目录 1.基于SSM的洗衣房管理系统原生微信小程序LW参考示例 2.基于SpringBoot的宠物摄影网站管理系统LW参考示例 3.基于SpringBootVue的企业人事管理系统LW参考示例 4.基于SSM的高校实验室管理系统LW参考示例 5.基于SpringBoot的二手数码回收系统原生微信小程序LW参考示…...

[晕事]今天做了件晕事44 wireshark 首选项IPv4:Reassemble Fragented IPv4 datagrams

不知不觉&#xff0c;已经来到了晕事系列的第四十四个晕事。今天办的晕事和Wireshark查看网络包相关。说&#xff0c;在Wireshark的编辑-首选项协议里的IPv4协议&#xff0c;有一个参数设置是&#xff1a;Reassemble Fragented IPv4 datagrams。 这个参数的含义是指定Wireshar…...

Unity人工智能开发学习心得

在Unity中进行人工智能研究与应用主要集中在几个关键领域&#xff0c;包括使用Unity ML-Agents插件进行强化学习、利用神经网络技术和深度学习技术训练AI&#xff0c;以及基于行为树技术设计游戏人工智能。 ‌使用Unity ML-Agents插件进行强化学习‌&#xff1a;Unity ML-Agent…...

0911,类与类之间的关系,设计原则,工厂模式

01_figure.cc //简单工厂 #include <math.h> #include <iostream> #include <string> #include <memory>using std::cout; using std::endl; using std::string; using std::unique_ptr;//-------------------------------------------------// /…...

【2024最新版】零基础Python快速入门篇

完整代码已打包&#xff0c;需要的小伙伴可以戳这里 [学习资料] 安装和运行 1.安装 要使用"Python"首先要把它安装到你电脑里。打开 [Python官网]下载安装包。 在Windows上安装 打开安装包&#xff0c;选择"Use admin privileges when installing py.exe&qu…...

掌握Go语言中的映射、常量与指针

映射&#xff08;Maps&#xff09; Go语言中的映射&#xff08;map&#xff09;等同于其他编程语言中的哈希表。映射的最大优势是可以使用任何可比较的数据类型作为键&#xff0c;也就是所谓的“map key”或“键”。尽管Go语言中的映射并没有限制哪些数据类型可以作为键&#…...

@35岁的网安人 答应我拿下这些证书

一、CISP注册信息安全专业人员 注册信息安全专业人员(Certified Information Security Professional&#xff0c;简称“CISP")&#xff0c;中国信息安全测评中心依据中编办赋予的职能&#xff0c;建立和发展的一整套完整的信息安全保障人才培训体系。CISP证书是国家对信息…...

flutter Image

Flutter中&#xff0c;Image是一个用于显示图片的控件&#xff0c;可以显示网络图片、本地图片以及Asset中的图片。Image控件支持多种常见的图片格式&#xff0c;例如PNG、JPEG、GIF等。 const Image({super.key,required this.image,this.frameBuilder,this.loadingBuilder,th…...

基于RP2350 MCU的树莓派Pico 2开发板及MicroPython编程使用

2021年1月21日,树莓派基金会同时发布了第1代RP2040 MCU芯片和基于RP2040 MCU的第1代树莓派Pico开发板(Raspberry Pi Pico/ Raspberry Pi Pico 1)。2024年8月8日,树莓派基金会又发布了第2代RP2350 MCU芯片并推出了基于RP2350 MCU的第2代树莓派Pico开发板(Raspberry Pi Pico 2)…...

Docker数据挂载本地目录

docker内的数据映射可以不通过数据卷&#xff0c;直接映射到本地的目录。下面将以mysql容器示例&#xff0c;完成容器的数据映射。 注意&#xff1a;每一个不同的镜像&#xff0c;将来创建容器后内部有哪些目录可以挂载&#xff0c;可以参考DockerHubDocker Hub Container Ima…...

身份证实名认证接口如何用C#实现

一、什么是身份证实名认证&#xff1f; 身份证实名认证又叫身份证实名核验、身份证二要素、身份实名核验、身份证验证&#xff0c;输入姓名、身份证号&#xff0c;校验此两项是否匹配&#xff0c;同时返回生日、性别、籍贯等信息&#xff0c;同时支持港澳台证件核验。 二、身…...

Java开发者无痛丝滑入门Python

哈喽各位道友&#xff0c;经过两周的更新&#xff0c;凡人编程传的第一个“系列”学习笔记《Python基础》已经全部上线啦&#xff0c;现在免费分享给大家&#xff0c;学习路线在下面&#xff0c;点击链接即可跳转对应笔记。 这套笔记有什么不一样的地方呢&#xff1f;这套笔记…...

使用 curl 命令直接测试 Taotoken 聊天补全接口连通性与返回

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 使用 curl 命令直接测试 Taotoken 聊天补全接口连通性与返回 在开发或调试过程中&#xff0c;有时你可能需要绕过高级 SDK&#xf…...

企业邮箱迁移技术方案:从旧邮箱平滑迁移至阿里 / 网易 / 谷歌

前言企业发展过程中&#xff0c;更换企业邮箱服务商属于常见运维需求&#xff0c;不少行政与运维人员担心迁移过程出现邮件丢失、通讯录错乱、收发中断等问题。掌握标准化迁移方案&#xff0c;可实现新旧邮箱无缝过渡&#xff0c;不影响日常商务对接与对内办公。本文分享通用迁…...

Claude Code质量崩了?Anthropic认错;3人+100个AI月烧130万美元,炸了

每天更新&#xff0c;带你读懂科技圈。 今日看点&#xff1a; Anthropic正式发布Claude Code质量事故复盘&#xff1b;OpenClaw之父晒出130万美元月账单——3人100个AI agent震撼业界&#xff1b;Hermes团队砍掉预训练六成成本&#xff1b;GitHub Copilot推桌面应用狙击AI编程对…...

【LangChain 】从一行 LCEL 代码,理解 LangChain 管道操作符 `|` 的自动转换机制

从一行 LCEL 代码&#xff0c;理解 LangChain 管道操作符 | 的自动转换机制一、从一个代码片段说起 先看这段处理用户反馈的 LCEL 代码&#xff1a; processing_chain (extract_chain| RunnablePassthrough.assign(analysislambda x: analysis_chain.invoke(x["original_…...

ESP32S3驱动1.3寸圆形AMOLED屏(RM67162芯片)的完整避坑指南:从SPI配置到LVGL局部刷新修复

ESP32S3驱动1.3寸圆形AMOLED屏&#xff08;RM67162芯片&#xff09;全流程实战&#xff1a;从SPI配置到LVGL优化 这块1.3寸圆形AMOLED屏幕以其出色的显示效果和独特的外形设计&#xff0c;在智能穿戴设备和小型嵌入式项目中越来越受欢迎。然而&#xff0c;当它与ESP32S3开发板结…...

高层次综合设计算法-常见问题记录(一)

一、算法设计思考的重点 1.定点化的陷阱 整数部分数据位宽不足造成的溢出&#xff1b; 舍入导致图像的视觉差异&#xff1b; 小数部分位宽不足导致精度不够&#xff0c;或者效果不佳&#xff1b;2.pipelin流水线的设计 普通变量造成的数据依赖问题&#xff0c;导致II达不到&…...

四大路径!CS保研生冲刺南京大学如何精准定位?

1. 南京大学计算机保研全景地图 对于计算机专业的保研生来说&#xff0c;南京大学就像一座蕴藏着丰富矿藏的山脉&#xff0c;不同院系代表着不同的矿脉。作为国内顶尖高校&#xff0c;南大计算机相关学科分布在四个主要院系&#xff1a;计算机科学与技术系&#xff08;传统强系…...

ZYNQ启动太慢?从FSBL到U-Boot的完整性能分析与优化实战

ZYNQ启动太慢&#xff1f;从FSBL到U-Boot的完整性能分析与优化实战 在嵌入式系统开发中&#xff0c;启动时间往往是衡量产品性能的关键指标之一。对于基于Xilinx ZYNQ平台的产品&#xff0c;从按下电源键到系统完全就绪&#xff0c;这中间经历的毫秒级延迟可能决定着一个工业控…...

从零开始理解阵列信号处理:用Python模拟阵列流形与波数响应

从零开始理解阵列信号处理&#xff1a;用Python模拟阵列流形与波数响应 阵列信号处理是雷达、声纳和无线通信等领域的核心技术之一。对于初学者来说&#xff0c;面对复杂的数学公式和抽象概念常常感到无从下手。本文将采用实践优先的方法&#xff0c;通过Python代码实现阵列流形…...

云端IDE开发CircuitPython:VS Code EDU实战指南与工具链解析

1. 项目概述&#xff1a;当CircuitPython遇上云端IDE如果你玩过像Adafruit的Metro M4、Raspberry Pi Pico这类微控制器板子&#xff0c;对CircuitPython一定不陌生。它让硬件编程变得像写Python脚本一样简单&#xff0c;code.py一保存&#xff0c;板子上的LED立马就能闪起来。但…...