[算法]第一集 递归(未完待续)

embedded/2024/9/22 18:35:03/

递归啊递归,说简单简单,说难难。

首先我们要知道

一、什么是递归?

我们再C语言和数据结构里都用了不少递归,这里就不多详细介绍。

递归简单来说就是函数自己调用自己的情况

二、为什么要用递归呢?

本质来说其实就是我们在解决一个问题后出现相同的问题,解决这个问题后会再出现相同的问题。我们解决这些问题的方式一样,所以就出现了函数自己调用自己。

三、如何加深理解递归?

以下的步骤由浅入深

  1. 首先,你需要会画递归展开图
  2. 当你会画递归展开图时,下面要刷刷题,先从简单的二叉树中的题目来刷,这种一般比较容易
  3. 当上面都完成后,下面我们要做到的就是能够宏观的去看递归的过程,宏观的去看递归的过程需要:
    1. 不要一味的在意递归的过程
    2.  尽量把递归函数当作一个黑盒
    3. 相信这个黑盒的实力

四、如何写好一个递归

  1. 找到相同的问题(把主问题分解成若干个子问题)--->函数头的设计
  2. 只需要关心某一个子问题是如何解决得---->函数体的书写
  3. 注意递归函数的出口,避免死循环

五、题目实战

1,经典汉诺塔问题

面试题 08.06. 汉诺塔问题 - 力扣(LeetCode)

这道题属于是我们接触递归后解决的第一道问题,很多人做完汉诺塔后,知道了汉诺塔要用递归解决,那么你知道为什么汉诺塔要用递归吗?

1)如何解决汉诺塔问题

我们可以先假设,三个柱子为A、B、C,盘子数量问n,盘子开始在A上,我们需要把它放到C上。

当n=1时 我们只需要一次操作,把A上的盘子转移到C上。

当n=2时

我们需要把盘子全部转移到C上,所以我们需要先把大的盘子转移到C上,所以我们需要先把上面的盘子转移到B上,把A上最大的盘子转移到C上

当n=3时,此时A上右三个盘子,

我们要把A上的盘子全部移到C上,所以我们需要把A上最大的盘子先移动到C,所以我们需要把A上较小的两个盘子移到B上,这时我们可以把它转化成n=2来解,此时的C是B,B是C。

当我们想出这个思路时,我们的递归思路是不是来了呢?

2)为什么呢用递归

所以我们为什么要用递归呢?

因为我们解决这个汉诺塔问题时,我们可以把它分解成若干的子问题。

3)如何编写递归代码?

1.重复子问题->函数头

将x柱上的n个盘子,借助y柱,转移到z柱上——>void dfs(x,y,z,n)

2.只关心某一个子问题在做什么->函数体

我们只需要先移动上n-1个,即调用dfs(x,z,y,n-1),然后x——>z,然后dfs(y,x,z,n-1)

3.递归的出口

n=1时,x—— >z

4) 代码解决
class Solution {
public:void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {int n = A.size();dfs(n, A, B, C);}void dfs(int n, vector<int>& A, vector<int>& B, vector<int>& C){if (n == 1){C.push_back(A.back());A.pop_back();return;}dfs(n-1, A, C, B);    // 将A上面n-1个通过C移到BC.push_back(A.back());  // 将A最后一个移到CA.pop_back();          // 这时,A空了dfs(n-1, B, A, C);     // 将B上面n-1个通过空的A移到C}
};

如果对于代码有疑问的可以自己画画递归展开图

2.合并两个有序链表

1)题意解析

2)算法原理

解法:递归——>重复子问题

1)重复子问题——>函数头的设计

这个很明显,就是合并两个有序链表——>Node*dfs(l1,l2)

2)只关心某一个子问题在做什么->函数体

1.比大小

2.(假设l1较小)l1->next=dfs(l1->next,l2)

3.return l1

3)递归的出口

3)代码解决
class Solution {
public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if (l1 == nullptr) {return l2;} else if (l2 == nullptr) {return l1;} else if (l1->val < l2->val) {l1->next = mergeTwoLists(l1->next, l2);return l1;} else {l2->next = mergeTwoLists(l1, l2->next);return l2;}}
};

本题结束。

4)小总结

1)迭代(循环)和递归

它们都能解决重复的子问题,所以我们一般的代码都能递归改循环,循环改递归。

但是为什么有些代码递归改循环麻烦,有些代码循环改递归麻烦呢?

这个问题我们可以像看一下这个例子,比如汉诺塔问题吧,我们不是画过递归展开图吗?不少人肯定发现了,我们没的递归展开图和树的深度优先搜索极为相似。

可以这么说,递归展开图,其实就是对一棵树做一次深度优先遍历(dfs)

所以,我们可以得出当递归展开图,如上图,比较复杂时,这个时候递归改循环就比较困难!

那么什么时候递归改循环简单呢?我们根据上面的结论可以反推出来,当递归展开图简单时,递归改循环简单!如下图:

我们也可以举一个实例,比如遍历数组

假设我们有一个num数组

我们用循环写一个遍历并打印

for(int i=0;i<num.size();++i)
{
cout<<num[i[<<" ";
}

我们用递归写个函数呢?
 

void dfs(vector<int>& num,int i)
{if(i==num.size())return;cout<<num[i]<<" ";dfs(num,i+1)
}

3.反转链表

1)题意解析

2)算法原理

解法:递归——>重复子问题

本题我们可以从两个视角进行解决:

视角一:从宏观看待


http://www.ppmy.cn/embedded/92863.html

相关文章

目标检测——GDXray数据集转为YOLO格式

关于该数据集的介绍可以看我写的另一篇博客&#xff1a;链接 论文题目&#xff1a;《GDXray: The Database of X-ray Images for Nondestructive Testing》论文链接&#xff1a;https://link.springer.com/article/10.1007/s10921-015-0315-7 Github链接&#xff1a; https:…

14. 最长公共前缀【 力扣(LeetCode) 】

一、题目描述 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 二、测试用例 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl"示…

Topaz Video AI——视频修复

一、Topaz Video AI 介绍及使用 Topaz Video AI 是一款基于人工智能的视频增强和修复软件&#xff0c;主要用于提升视频质量、去噪、插帧和分辨率提升。它利用深度学习技术对视频进行智能化处理&#xff0c;使得视频看起来更加清晰和流畅。Topaz Video AI 特别适合那些需要修复…

Redis相关

一、BitMap 1. SETBIT对key存储的字符串值&#xff0c;设置或清除指定偏移量的位&#xff0c;位的设置和清除取决于value参数&#xff0c;可以是0或者1&#xff0c;如果key不存在&#xff0c;自动创建一个新的字符串值&#xff0c;offset参数必须大于或等于0&#xff0c;小于2…

使用Spring与JDK动态代理实现事务管理

使用Spring与JDK动态代理实现事务管理 在现代企业级应用开发中&#xff0c;事务管理是一项关键的技术&#xff0c;它可以保证一系列操作要么全部成功&#xff0c;要么全部失败&#xff0c;从而确保数据的一致性和完整性。Spring框架提供了强大的事务管理能力&#xff0c;但有时…

24 - clearerr()函数

文章目录 1 函数原型2 参数3 返回值 1 函数原型 clearerr()函数&#xff1a;清除指定流stream的错误指示符&#xff0c;函数原型如下&#xff1a; void clearerr ( FILE * stream );cstdio库描述如下&#xff1a; Clear error indicators 1. Resets both the error and the …

YOLOv8进 | 检测头 | 小目标遮挡物性能提升的检测头Detect_MultiSEAM【完整代码】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

OSPF 命令 Default-router-advertise 之 always 选项解析

1、关于 default-route-advertise 命令 Ospf 是可以通过 import-route 命令引入外部路由的&#xff0c;但很少有人会注意到&#xff0c;在默认情况下&#xff0c;ospf 是不会引入来自外部路由的缺省路由的。 但 ospf 有一个变通的方法&#xff0c;就是通过 default-route-adv…