【递归、搜索和回溯】递归、搜索和回溯介绍及递归类算法例题

个人主页 : zxctscl
专栏 【C++】、 【C语言】、 【Linux】、 【数据结构】、 【算法】
如有转载请先通知

文章目录

  • 递归、搜索和回溯
    • 递归
    • 搜索VS 深度优先遍历 VS 深度优先搜索 VS 宽度优先遍历 VS 宽度优先搜索 VS 暴搜
    • 回溯与剪枝
  • 1 面试题 08.06. 汉诺塔问题
    • 1.1 分析
    • 1.2 代码
  • 2 21. 合并两个有序链表
    • 2.1 分析
    • 2.2 代码
    • 2.3 总结
  • 3 206. 反转链表
    • 3.1 分析
    • 3.2 代码
  • 4 24. 两两交换链表中的节点
    • 4.1 分析
    • 4.2 代码
  • 5 50. Pow(x, n)
    • 5.1 分析
    • 5.2 代码

递归、搜索和回溯

搜索是递归的一个分支,回溯是搜索里面的分支。

递归

  1. 什么是递归?
    在数据结构二叉树、快排和归并都有提到
    递归就是函数自己调用自己的情况

  2. 为什么会用到递归
    二叉树的后序遍历:左子树、右子树、根
    在快排中,先选择一个基准元素将数组分成两部分,左边排一下序,右边排一下序
    在归并排序中,选择一个中间点,把数组平分,先让左边排一下序,再让右边排一下序,再把两个有序数组合并
    在这里插入图片描述
    递归的本质:
    主问题->相同的子问题
    子问题->相同的子问题

  3. 如何理解递归
    (1)递归展开的细节图
    (2)二叉树的题目
    (3)宏观看待递归过程:
    一、不要在意递归细节展开图
    二、把递归的函数当成一个黑盒(具体里面如何操作的并不关心,只要能输出结果)
    三、相信这个黑盒一定能完成这个任务
    在这里插入图片描述

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

搜索VS 深度优先遍历 VS 深度优先搜索 VS 宽度优先遍历 VS 宽度优先搜索 VS 暴搜

  1. 深度优先遍历 VS 深度优先搜索->dfs
    宽度优先遍历 VS 宽度优先搜索->bfs
    一定程度上等同
    遍历是形式,目的是搜索
    在这里插入图片描述

  2. 关系图
    暴力枚举一遍所有的结果
    搜索(也叫暴搜)分为两种:dfs、 bfs
    递归主要是dfs

  3. 拓展搜索问题
    全排列 树状图
    在这里插入图片描述

回溯与剪枝

  1. 回溯
    回溯本质就是深搜

1 面试题 08.06. 汉诺塔问题

在这里插入图片描述

1.1 分析

  1. 题目解析
    中间摆放的时候必须是小盘子在大盘子的上面

  2. 算法原理
    (1)如何解决汉洛塔问题?
    当N=1,直接把A上面的盘子放到C上。
    当N=2,想要把最大的盘子放到C上,此时先得把上面的小盘子放到B上,当把A剩下的大盘子直接移动到C上后,再将B上的小盘子放到C上。
    当N=3时候,首先把A最下面盘子移动到C,前提就得将A上面的2个盘子放到B上(就像N=2时,把上面两个盘子借助C移到B上)再将A最下面的盘子放到C上,最后把B上的盘子移到C上。
    当N=4时,首先把A最下面盘子移动到C,前提就得将A上面的3个盘子(当做一个整体)放到B上(就像N=3时,把上面两个盘子借助C移到B上)再将A最下面的盘子放到C上,最后把B上的盘子移到C上。

    当N=n,也同样是首先把A最下面盘子移动到C,前提就得将A上面的n-1个盘子(当做一个整体)放到B上(就像N=n-1时,把上面两个盘子借助C移到B上)再将A最下面的盘子放到C上,最后把B上的盘子移到C上。

在这里插入图片描述
(2)为什么用递归?
大问题->相同问题的子问题
子问题->相同问题的子问题

(3)如何编写递归代码?
一、重复子问题->函数头
先把X柱子上的盘子,借助Y柱子,转移到Z柱子上
需要三个柱子,还有盘子的数量,就需要传四个参数

void dfs(X,Y,Z,int n)

二、只关心某一个子问题在做什么->函数体
(1)将X上面n-1盘子,借助Z,转移到Y上dfs(X,Z,Y,n-1)
(2)把A最下面盘子移到Z上
(3)再将Y上n-1个盘子借助X移到Z上dfs(Y,X,Z,n-1)
在这里插入图片描述

三、递归出口
当N=1时,把X上盘子放到Z上
在这里插入图片描述

  1. 编写代码

  2. 递归的细节展开图
    在这里插入图片描述

1.2 代码

class Solution {
public:void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {      dfs(A,B,C,A.size());     }void dfs(vector<int>& A, vector<int>& B, vector<int>& C,int n){if(n==1){C.push_back(A.back());A.pop_back();return;}dfs(A,C,B,n-1);C.push_back(A.back());A.pop_back();dfs(B,A,C,n-1);}
};

2 21. 合并两个有序链表

在这里插入图片描述

2.1 分析

算法原理
解法:递归

两个链表都是升序,找两个链表头结点中较小的节点作为返回的头节点。
当选择头节点之后,就是将剩下的两个链表合并
在这里插入图片描述

(1)重复子问题->函数头
合并两个有序链表 Node*dfs(l1,l2)

(2)只关心某一个子问题在做什么事情->函数体的设计
一、比大小
二、如果l1较小 :l1->next=dfs(l1->next,l2)
三、return l1

(3)递归出口

谁为空返回另一个

在这里插入图片描述

2.2 代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2){if(list1==nullptr)return list2;if(list2==nullptr)return list1;if(list1->val<=list2->val){list1->next=mergeTwoLists(list1->next,list2);return list1;}else{list2->next=mergeTwoLists(list1,list2->next);return list2;}}};

2.3 总结

  1. 递归VS循环 什么时候用循环舒服?什么时候用递归舒服?
    递归和循环都是重复子问题,递归和循环之间可以相互转换

递归图越复杂,递归就越舒服

  1. 递归VS深搜
    递归展开图,其实就是对一棵树做一次深度优先搜索遍历(dfs)
    在这里插入图片描述

3 206. 反转链表

在这里插入图片描述

3.1 分析

解法:递归

第一个视角:从宏观角度

  1. 把当前节点后面链表先逆置,并且把头结点返回;
  2. 把当前节点添加到逆置链表的后面
  3. 当遇到null就返回
    在这里插入图片描述

第二个视角:将链表看成一棵树
先找到叶子结点,再返回
在这里插入图片描述

在这里插入图片描述

3.2 代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* reverseList(ListNode* head) {if(head==nullptr||head->next==nullptr)return head;ListNode* newhead=reverseList(head->next);head->next->next=head;head->next=nullptr;return newhead;}
};

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

在这里插入图片描述

4.1 分析

解法:递归
视角:从宏观角度看待递归

想要两两逆置,把后面的那堆先两两逆置一下,后面的调用完dfs后,再返回后面部分的头结点,再把前面两个交换一下,把交换后的连起来。
在这里插入图片描述

在这里插入图片描述

4.2 代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head) {if (head == nullptr || head->next == nullptr)return head;ListNode* tmp = swapPairs(head->next->next);ListNode* ret = head->next;head->next->next = head;head->next = tmp;return ret;}
};

5 50. Pow(x, n)

在这里插入图片描述

5.1 分析

解法:一、暴力循环
对于太大的幂是会超时的

二、快速幂
实现快速幂:(1)递归(2)循环

这里用递归

如果快速得到3的16次方,得到3的8次方就行,要3的8次方得到3的4次方就行,要得到3的4次方,得到3的2次方就行,要得到3,就直接3乘1就行。这里时间复杂度就是logN

那么如果除不进时,21/2除不进,就能可以分为3的10次方乘3的10次方再乘3就行,一直这样
在这里插入图片描述

(1)重复子问题->函数头

int pow(x,n)

(2)只关心某一个子问题在做什么事情->函数体的设计
先求出n/2的次方是多少: tmp=pow(x,n/2)
再判断一下n/2能不能整除,不能整除再成上x:return n%2==0?tmp*tmp*x

(3)递归出口
如果n等于0,就返回1

细节问题:

  1. n可能是负数
    要提前把负数转成正数,再用1除一下
    在这里插入图片描述

  2. n可能是-2^31
    -2^31负数太大,转成正数会存不下,int正整数最大是2^31-1
    可以提前把n的类型强转为long long
    在这里插入图片描述

5.2 代码

class Solution {
public:double myPow(double x, int n) {return n<0?1.0/pow(x,-(long long)n):pow(x,n);}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/904825.shtml

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

相关文章

快手618购物节招商启动,国补可叠加跨店满减等大促补贴

5月8日&#xff0c;快手电商在杭州召开「破峰2025」商家大会。会上&#xff0c;快手电商C端产品负责人孔慧介绍了快手电商全域经营年度策略以及新锐商家长效经营方法论&#xff0c;并宣布快手618购物节招商报名正式启动。 信任社区生态是快手电商发展的基石&#xff0c;2025年…

AI服务器通常会运用在哪些场景当中?

人工智能行业作为现代科技的杰出代表&#xff0c;在多个领域当中发展其强大的应用能力和价值&#xff0c;随之&#xff0c;AI服务器也在各个行业中日益显现出来&#xff0c;为各个行业提供了强大的计算能力和处理能力&#xff0c;帮助企业处理复杂的大规模数据&#xff0c;本文…

MySQL高可用方案全攻略:选型指南与AI运维实践

MySQL高可用方案全攻略:选型指南与AI运维实践 引言:当数据库成为业务生命线 在数字化时代,数据库就是企业的"心脏"。一次数据库宕机可能导致: 电商网站每秒损失上万元订单游戏公司遭遇玩家大规模流失金融系统引发连锁反应本文将为你揭秘: MySQL主流高可用方案…

电位器如何接入西门子PLC的模拟量输入

1.设计思考 我现在手上有一个三线10kΩ的滑动变阻器&#xff0c;想让其当作模拟量接入西门子PLC中&#xff0c;外部改变电阻&#xff0c;PLC程序中能看到对应的阻值或电压&#xff0c;这样可以练习模拟量输入这个知识点&#xff01; 2.了解模拟量的种类 模拟量一般有电压型和…

MongoDB培训文档大纲(超详细)

第一章&#xff1a;引言 1.1 什么是MongoDB&#xff1f; 定义&#xff1a; MongoDB 是一个开源的 NoSQL 数据库&#xff0c;基于文档模型存储数据。它允许使用 JSON 格式&#xff08;更具体地说是 BSON&#xff09;来存储结构化和半结构化数据。MongoDB 是一个高性能、可扩展且…

新闻发稿筛选媒体核心标准:影响力、适配性与合规性

1. 评估媒体影响力 权威性与公信力&#xff1a;优先选择央级媒体&#xff0c;其报道常被其他平台转载&#xff0c;传播链条长&#xff0c;加分权重高。 传播数据&#xff1a;参考定海区融媒体中心的赋分办法&#xff0c;关注媒体的阅读量、视频播放量等指标&#xff0c;如阅读…

ATH12K驱动框架架构图

ATH12K驱动框架架构图 ATH12K驱动框架架构图(分层描述)I. 顶层架构II. 核心数据结构层次关系III. 主要模块详解1. 核心模块 (Core)2. 硬件抽象层 (HAL)3. 无线管理接口 (WMI)4. 主机目标通信 (HTC)5. 复制引擎 (CE)6. MAC层7. 数据路径 (DP)IV. 关键数据流路径1. 发送数据流 …

sqli-labs靶场18-22关(http头)

目录 less18&#xff08;user-agent&#xff09; less19&#xff08;referer&#xff09; less20&#xff08;cookie&#xff09; less21&#xff08;cookie&#xff09; less22&#xff08;cookie&#xff09; less18&#xff08;user-agent&#xff09; 这里尝试了多次…

​​​​​​​MySQL数据库故障排查指南

一、连接类问题 1. 无法连接数据库 现象&#xff1a;应用或客户端无法连接MySQL服务。 排查步骤&#xff1a; 检查服务状态&#xff1a; bash 复制 下载 systemctl status mysqld # 检查MySQL是否运行 netstat -tuln | grep 3306 # 确认3306端口是否监听 检查网络问…

Github 热点项目 Cursor开源代替,AI代理+可视化编程!支持本地部署的隐私友好型开发神器。

Void编辑器今天必须拥有姓名&#xff01;作为总星数近1.5万的顶流开源工具&#xff0c;它用三大绝活圈粉无数&#xff1a;① 隐私党狂喜&#xff01;所有AI对话直连模型商&#xff0c;你的代码数据绝不留在别人服务器&#xff1b;② 自带时光机功能&#xff0c;AI修改代码时自动…

Quorum协议原理与应用详解

一、Quorum 协议核心原理 基本定义 Quorum 是一种基于 读写投票机制 的分布式一致性协议&#xff0c;通过权衡一致性&#xff08;C&#xff09;与可用性&#xff08;A&#xff09;实现数据冗余和最终一致性。其核心规则为&#xff1a; W&#xff08;写成功副本数&#xff09; …

PyTorch_自动微分模块

自动微分 (Autograd) 模块对张量做了进一步的封装&#xff0c;具有自动求导功能。自动微分模块是构成神经网络训练的必要模块&#xff0c;在神经网络的反向传播过程中&#xff0c;Autograd 模块基于正向计算的结果对当前的参数进行微分计算&#xff0c;从而实现网络权重参数的更…

34.笔记1

今天&#xff0c;我们回顾回顾曾经的知识。 1.二分 还记得当初的二分吗&#xff1f; 1.一开始的二分 就像下面这个故事&#xff1a; 有一只老鼠&#xff0c;躲在10个大瓷瓶后面。你的任务就是抓住这只老鼠&#xff0c;但在抓的过程会导致你选择的大瓷瓶成为分子碎片。 如…

云原生环境下服务治理体系的构建与落地实践

📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:服务治理正在从“框架能力”向“平台能力”演进 随着微服务架构逐步成熟,越来越多的企业开始向云原生迁移,Kubernetes、Service Mesh、Serverless 等新兴技术不断推动系统的基础设施演进。 与…

读取传感器发来的1Byte数据:分低位先行和高位先行的处理方法

目录 一、写在前面 二、伪代码的逻辑实现 1、从高位到低位 2、从低位到高位 一、写在前面 在接收数据之前我们需要事先知道数据的发送规则&#xff0c;是高位先行还是低位先行&#xff0c;并按照规则接收数据&#xff0c;否则收到的数据很可能是错的 高位先行&#xff1a;…

C++ - 函数重载

概念 函数重载允许在同一作用域内定义多个同名函数&#xff0c;但这些函数的参数要满足&#xff1a;参数类型、参数个数&#xff0c;参数顺序不同&#xff08;满足三个中的一个&#xff09;&#xff0c;才能使用函数重载 #include <iostream> using namespace std;// 1…

EEG设备的「减法哲学」:Mentalab Explore如何用8通道重构高质量脑电信号?

在脑电图&#xff08;EEG&#xff09;研究领域&#xff0c;选择适配的工具是推动研究进展的重要步骤。Mentalab Explore 以其便捷性和高效性&#xff0c;成为该领域的一项创新性解决方案。研究者仅用较少的 EEG 通道即可完成实验&#xff0c;并且能够确保数据的高质量。其搭载的…

Vue3 路由配置与跳转传参完整指南

目录 一、路由配置 1. 基本路由配置 2. 动态路由配置 3. 可选参数配置 二、路由跳转与传参 1. 声明式导航 (模板中) 2. 编程式导航 (JavaScript中) 三、参数接收 1. 接收动态路由参数 2. 接收查询参数 3. 监听参数变化 四、高级用法 1. 路由元信息 2. 路由守卫控…

Vibe Coding: 优点与缺点

如果你最近在开发圈子里,你很可能听说过这个新趋势"vibe coding"(氛围编程)。 我只能说我对此感受复杂。以下是原因。 优势 在构建新项目时,靠着氛围编程达到成功感觉很自由!但对于遗留代码来说情况就不同了,尽管也不是不可能。 实时反馈和快速迭代 Cursor(…

7:点云处理—眼在手外标定

1.制作模板 dev_update_off ()dev_set_color (green)dev_close_window ()WindowHeight:740WindowWidth :740dev_open_window(0, 0, 540, 540, black, WindowHandle)Instruction : [Rotate: Left button,Zoom: Shift left button,Move: Ctrl left button]read_object_mod…