【算法】递归

ops/2024/9/24 8:06:04/



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、汉诺塔
  • 二、合并两个升序链表
  • 三、反转链表
  • 四、两两交换链表的结点
  • 五、Pow(x, n)
  • 总结

引言

通过递归的视角,来宏观看待一些问题,从而深入了解递归,为搜索打下基础。

一、汉诺塔


思路:

  1. 函数头设计:把x柱子上的n个盘子,以y柱子为辅助,转移到z柱子上
  2. 先将x上n-1个盘子移到y上,再将x上最下面的盘子移到z,最后再将y上n-1个盘子移到z上
  3. 终止条件:当n==1时,直接将x的盘子移到z上即可
class Solution
{
public:void dfs(vector<int>& x, vector<int>& y, vector<int>& z, int n){if(n == 1){z.push_back(x.back());x.pop_back();return;}dfs(x, z, y, n-1);z.push_back(x.back());x.pop_back();dfs(y, x, z, n-1);}void hanota(vector<int>& A, vector<int>& B, vector<int>& C){dfs(A, B, C, A.size());}
};

二、合并两个升序链表


思路:

  1. 先比较 l1 和 l2 头结点值的大小
  2. 选取较小的结点,将其下一个节点和另一个链表头结点进行合并
  3. 终止条件:当一个链表头结点为空时,返回另一个链表头结点
class Solution
{
public:ListNode* dfs(ListNode* l1, ListNode* l2){if(l1 == nullptr) return l2;if(l2 == nullptr) return l1;if(l1->val <= l2->val){l1->next = dfs(l1->next, l2);return l1;}else{l2->next = dfs(l1, l2->next);return l2;}}ListNode* mergeTwoLists(ListNode* list1, ListNode* list2){return dfs(list1, list2);}
};

三、反转链表


思路:

  1. 先将链表头结点的下一位进行反转,再将当前头结点链接在反转链表的尾部
  2. 终止条件:头结点为空,或只有一个节点
class Solution
{
public:ListNode* dfs(ListNode* head){if(!head || !head->next) return head;ListNode* rhead = dfs(head->next);head->next->next = head;head->next = nullptr;return rhead;}ListNode* reverseList(ListNode* head){return dfs(head);}
};

四、两两交换链表的结点


思路:

  1. 先将头两个结点后的结点进行两两交换,再将头两个结点进行交换
  2. 终止条件:头结点为空,或只有一个节点
class Solution
{
public:ListNode* dfs(ListNode* head){if(!head || !head->next) return head;ListNode* newhead = dfs(head->next->next);ListNode* next = head->next;next->next = head;head->next = newhead;return next;}ListNode* swapPairs(ListNode* head){return dfs(head);}
};

五、Pow(x, n)


思路:

  1. 快速幂:时间复杂度为O(logN),普通方法O(N)会超时
  2. 先算出n/2的幂tmp,再判断n是否为偶数,若为偶数,则返回tmp * tmp,若为奇数,则返回 tmp * tmp * x
  3. 终止条件:若n==0,则返回1(任何数的0次方都为1)
  4. 若n < 0,则计算1 / dfs(x, -n)(注意-n可能会数据溢出,所以改成long long)
class Solution
{
public:double dfs(double x, long long n){if(n == 0) return 1;auto tmp = dfs(x, n/2);return n%2==0 ? tmp*tmp : tmp*tmp*x;}double myPow(double x, long long n){return n>=0 ? dfs(x, n) : 1/dfs(x, -n);}
};

总结

对于一个重复的子问题,我们既可以用迭代(循环),也可以用递归。

递归的展开图,其实就是对一棵树进行深度优先遍历(dfs)

那么,什么时候用迭代舒服,什么时候用递归舒服呢?

  • 当重复子问题只有一个分支时,用循环合适
  • 当重复子问题有多个分支,用递归合适

真诚点赞,手有余香


http://www.ppmy.cn/ops/33072.html

相关文章

Unity 性能优化之数据面板(Statistics)(一)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、unity 统计数据面板&#xff08;Statistics&#xff09;1.Audio属性2.Graphics属性 二、什么是Draw Call&#xff1f;三、Unity3D stats也可以通过代…

小程序开发中遇到主包过大无法真机调试怎么解决

主包过大可能跟图片&#xff0c;音频&#xff0c;视频的大小数量有关 解决办法&#xff1a;可以让UI设计师帮忙压缩一下图片&#xff0c;也可以使用一些其他压缩软件进行压缩处理。这里推荐我常用的一个种 TinyPNG – Compress WebP, PNG and JPEG images intelligently。也可…

WPF之XmlDataProvider使用

1&#xff0c;WPF XAML支持数据提供&#xff08;DataProvider&#xff09;&#xff0c;但其提供的数据只供查看不可进行修改&#xff0c;删除&#xff0c;添加等。 数据提供者都继承自System.Windows.DataSourceProvider类&#xff0c;目前&#xff0c;WPF只提供两个数据提供者…

Matlab各个版本介绍、区别分析及推荐

MATLAB&#xff0c;由美国MathWorks公司出品&#xff0c;是一款广泛应用的商业数学软件。自其诞生之初&#xff0c;MATLAB便以其强大的矩阵计算能力、灵活的编程环境以及广泛的应用领域&#xff0c;赢得了全球科研工作者和工程师的青睐。本文将详细介绍MATLAB的各个版本&#x…

二叉树的前序遍历

目录 一、前言 二、前序遍历 三、递归 四、迭代 一、前言 接下来两天时间&#xff0c;我将详细整理二叉树的三种遍历方式---前序遍历、中序遍历、后序遍历。每种遍历方式我将主要从递归、迭代两种方式进行整理&#xff0c;之后我会单独整理Morris&#xff08;莫里斯&a…

【Linux系统编程】第十三弹---项目自动化构建工具-make/Makefile

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、背景 2、编写makefile 2、make原理 3、理解makefile 4、优化makefile 总结 1、背景 ★ 会不会写makefile&#xff0c;从…

mysql 指定根目录 迁移根目录

mysql 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、初始化mysql前就手动指定mysql根目录为一个大的分区(支持动态扩容)&#xff0c;事前就根本上解决mysql根目录空间不够问题3.1.0、方法思路3.1.1、卸载mariadb3.1.2、下载Mysql安装包3.1.3、安装Mysql 8.353…

Mysql:常见问题

常见问题 一、查询缓存和缓冲池二、为什么表数据删掉一半,表文件大小不变?三、为何选择B+Tree作为索引的数据结构?四、为什么建议用自增ID做主键?五、正常运行的实例,数据写入后的最终落盘,是从redo log更新过来的还是从buffer pool更新过来的?一、查询缓存和缓冲池 1、缓…