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

【递归、搜索与回溯】专题一:递归(一)

📝前言说明:

  • 本专栏主要记录本人递归,搜索与回溯算法的学习以及LeetCode刷题记录,按专题划分
  • 每题主要记录:(1)本人解法 + 本人屎山代码;(2)优质解法 + 优质代码;(3)精益求精,更好的解法和独特的思想(如果有的话)
  • 文章中的理解仅为个人理解。如有错误,感谢纠错

🎬个人简介:努力学习ing
📋本专栏:C++刷题专栏
📋其他专栏:C语言入门基础,python入门基础,C++学习笔记,Linux
🎀CSDN主页 愚润泽

你可以点击下方链接,进行该专题内不同子专题的学习

点击链接开始学习
导论递归 (一)、递归 (二)
二叉树的深搜穷举 vs 暴搜 vs 深搜
回溯 vs 剪枝综合练习
FloodFill算法记忆化搜索

题目

  • 面试题 08.06. 汉诺塔问题
    • 个人解
  • 21. 合并两个有序链表
    • 优质解
  • 总结
    • 循环(迭代) vs 递归
    • 递归 vs 深搜


面试题 08.06. 汉诺塔问题

题目链接:https://leetcode.cn/problems/hanota-lcci/description/
在这里插入图片描述

个人解

思路:

  • 分析问题
    • n == 1 时,直接把盘子从 A 移到 C;(递归出口)
    • n > 1 时
      • 先把上面 n - 1 个盘子从 A 移到 B(子问题);
      • 再将最大的盘子从 A 移到 C;
      • 再将 B 上 n - 1 个盘子从 B 移到 C(子问题)。
  • 子问题确定函数头:把 n - 1个盘子从 A,借助 C,移动到 B
    • move(int n, vector<int>& source, vector<int>& auxiliary, vector<int>& target)
  • 单个子问题解决方法:即上面 n > 1的处理流程
  • 递归出口:即:n == 1的处理流程

用时:10:00
屎山代码:

class Solution {
public:void move(int n, vector<int>& source, vector<int>& auxiliary, vector<int>& target){if(n == 1) // 当只有一个盘子,直接移动{target.emplace_back(source.back());source.pop_back();return;}// 把前 n - 1 个盘子移动到辅助柱子move(n - 1, source, target, auxiliary); // 移动第 n 个盘子target.push_back(source.back());source.pop_back();// 在把 前 n - 1 个盘子从辅助盘子移动回来move(n - 1, auxiliary, source, target);}void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {move(A.size(), A, B, C);}
};

时间复杂度:O( 2 n 2^n 2n)
空间复杂度:O(n)


21. 合并两个有序链表

题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/description/
在这里插入图片描述

优质解

思路:

  • 分析问题:
    • 每次进行两个链表的头结点比较,然后提取出较小的头结点
    • 再用提出的头结点,链接两个链表(其中一个的头结点被提出)合并好后的结果
  • 子问题:合并有序链表
    • 函数头:Node* dfs(l1, l2); // 给两个链表,返回提出的头结点
  • 单个子问题解决方法:
    • 比较大小,记录小的头结点Node
    • 链接,假如l1->val < l2 -> val,则l1->next = dfs(l1 -> next, l2);
    • 返回合并后链表的头结点,return Node;
  • 递归出口:链表为空
    代码:
class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {if(list1 == nullptr || list2 == nullptr)return list1 == nullptr? list2 : list1; // 返回不为空那个,把没连接的部分链上if(list1 -> val < list2 -> val){list1 -> next = mergeTwoLists(list1 -> next, list2);return list1;}else{list2 -> next = mergeTwoLists(list1, list2 -> next);return list2;}}
};

时间复杂度:O(n1 + n2)
空间复杂度:O(min(n1, n2)),递归最深的那一次调用链的长度


总结

循环(迭代) vs 递归

循环和递归都是在处理重复子问题,那什么时候用循环,什么时候用递归?
适用场景:

  • 循环,当展开时,调用都是同一方向的调用(此时可以写成循环),如:迭代处理集合元素(i 的行为只有 – )
  • 递归,出现多种不同的调用自身(会选择不同方向的调用自身),如:树形结构的遍历,分治策略…

循环和递归展开图的特点:
循环遍历数组:
在这里插入图片描述
递归遍历二叉树:
在这里插入图片描述

循环和递归之间的代码可以相互转换。但是,对于递归转换成循环来说:因为函数体内部递归返回结果的时候,函数还没有完全执行完,所以要用一个栈来存储信息。就会有极大的消耗。

简单的转换代码:

在这里插入图片描述

递归 vs 深搜

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


🌈我的分享也就到此结束啦🌈
要是我的分享也能对你的学习起到帮助,那简直是太酷啦!
若有不足,还请大家多多指正,我们一起学习交流!
📢公主,王子:点赞👍→收藏⭐→关注🔍
感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

http://www.xdnf.cn/news/5641.html

相关文章:

  • Java面试高阶篇:Spring Boot+Quarkus+Redis高并发架构设计与性能优化实战
  • Maven 项目构建时编译错误问题排查与解决
  • Spring Boot整合Kafka实战指南:从环境搭建到消息处理全解析
  • 【MCP】魔搭社区MCP服务(高德地图、everything文件搜索)
  • Ai网站流式渲染总结
  • c语言第一个小游戏:贪吃蛇小游戏03
  • #在 CentOS 7 中手动编译安装软件操作及原理
  • 03.Golang 切片(slice)源码分析(二、append实现)
  • 视频监控汇聚平台EasyCVR安防视频监控小知识:视频监控系统与监视器安装
  • 【Redis实战篇】分布式锁-Redisson
  • 最新AI产品库哪个平台好?最新AI工具网站平台推荐
  • C++中的std::allocator
  • 神经生物学+图论双buff,揭示大脑语言系统的拓扑结构
  • Android学习总结之线程池篇
  • 脑机接口重点产品发展路径分析:以四川省脑机接口及人机交互产业攻坚突破行动计划(2025-2030年)为例
  • Matlab 短时交通流预测AR模型
  • 【C#】ToArray的使用
  • 将本地文件上传到云服务器上
  • Matlab 模糊控制节水洗衣机模型
  • Next.js 知识框架总结
  • 212. 单词搜索 II【 力扣(LeetCode) 】
  • windows下docker 运行 ros2humble arm64
  • day 23
  • VIC-2D 7.0 为平面样件机械试验提供全视野位移及应变数据软件
  • MySQL是如何加行级锁的
  • Java大师成长计划之第19天:性能调优与GC原理
  • C# 中 static的使用
  • 计算机网络核心技术解析:从基础架构到应用实践
  • 2025年阿里云大数据ACP高级工程师认证模拟试题(附答案解析)
  • 基于Vue3.0的高德地图api教程004:自定义绘制点的颜色/修改绘制点/删除绘制点