【Hello Algorithm】认识一些简单的递归

简介: 【Hello Algorithm】认识一些简单的递归

我在刚刚学习C语言的时候写过一个汉诺塔问题 大家可以参考下我之前写的这篇博客

汉诺塔问题

其实这个问题也可以这么解决

  • 我们设计六个函数 这六个函数分别代表从a到b 从a到c …
  • 但是实际上我们使用了一个函数就解决了上面六个函数才能解决的事

这就说明 我们可以使用增加参数的方式来增加递归函数的可能性

打印一个字符串全部的子序列

题目要求如下

假设字符串String str = “abc”,那么它的子序列有" "、a、b、c、ab、ac、bc、abc。依次从头往后拿,所有情况都枚举即可

我们回顾下题目实际上就是从第一个字符串开始我们考虑每个字符要和不要两种情况

那么我们可以设计这样子的一个递归函数

void process(string str ,int index , list<string> ans , string path)

这四个参数分别代表着

  • 我们要传入的字符串
  • 现在走到的位置
  • 答案
  • 目前为止拼接的字符串

我们每个递归函数内部只需要考虑当前字符是否拼接 之后传递给下一个递归函数即可

完整代码如下

  void process(const string& str ,int index , list<string>& ans , string path1)
  {
    if (str.length() == index)
    {
      ans.push_back(path1);
      return;    
    }    
    process(str , index + 1 , ans , path1);    
    process(str , index + 1 , ans , path1 + str[index]);    
  }

如果不允许有重复的字符串出现应该怎么做呢?

此时我们就可以使用 unordered_set 容器来自动去重即可

打印一个字符串的全排列

输入一个字符串 打印这个字符串的全排列

比如说给你一个字符串 abc

实际上就是给你一个字符集合 {a, b, c} 要求你将这三个字符随意组合出一个新的字符 共有多少种排列方式

实际上就是 3 x 2 x 1 一共六种

我们解决这个问题使用递归来解决 首先递归函数的声明如下

void  process(vector<char> lc , list<string>& ans , string path1)

代码如下

  void  process(vector<char> lc , list<string>& ans , string path1)    
  {    
    if (lc.size() == 0)    
    {    
      ans.push_back(path1);    
      return;    
    }    
    else    
    {    
      for (int i = 0; i < lc.size(); i++)    
      {    
        char cur = lc[i];    
        lc.erase(lc.begin() + i);    
        process(lc , ans , path1 + cur);                                                                                        
        lc.insert(lc.begin() + i , cur);    
      }    
    }    
  }  

解释下上面这段代码 我们每次都从集合中拿走一个元素 如果说集合被拿空了 那么此时的字符串肯定已经拼接完成了

如果集合还没空我们就一个个将这些字符串拼接起来 (注意! 如果你是将集合拼接在path中则要在最后还原path 如果是将path和cur一起传递则不用)

最后我们就能得到一个字符串的全排列了

742d31b8224e488696c42db51236e069.png

1734989da64341479f8777497b386c08.png

当然 我们上面写的其实是一种不太好的递归 因为它可变参数的设计不太行 这样子我们递归到动态规划就会很麻烦 优秀的递归设计应该是下面这样子的

  void process(vector<char>& nums , int index , vector<string>& ans)    
  {    
    if (nums.size() == index)    
    {    
      string ans1;    
      for (auto x : nums)    
      {    
        ans1 += x;    
      }    
      ans.push_back(ans1);    
      return;    
    }    
    else    
    {    
      for (size_t i = index ; i < nums.size() ; i++)    
      {    
        swap(nums[i] , nums[index]);    
        process(nums , index + 1 , ans);    
        swap(nums[i] , nums[index]);    
      }                                                                                                                         
    }    
  } 

给定我们一个原数组 我们从数组中选择一个字符作一号位

for (size_t i = index ; i < nums.size() ; i++)
swap(nums[i] , nums[index]);

选择完一号位之后我们再选二号位 之后依次递归即可

process(nums , index + 1 , ans);

如果要求字符串不重复应该怎么做呢?

如果要求字符串不重复 这里有两种方式

  1. 我们使用unordered_set容器来保存答案
  2. 进行剪枝

我们可以设置一个bool数组 如果说某个元素已经做个头了 我们就不让它做头了

未剪枝前

07142ac764854a56b0e5b9de8f45cd74.png剪枝代码

b07787a22d814803b00a76fa7b2d3d56.png

剪枝后

5d793b68267c45638172d84565bdd64f.png

不申请额外的空间 逆序输出一个栈

我们现在申请一个栈 现在它内部有 1 2 3 4 5 6

如果我们正常输出 应该是这样子的

185b2eb4e7f44d97ac66624654f689fc.png

现在我们要逆序这个栈的输出 我们可以这么做

void revprint(stack<int>& st)    
{    
  if (st.empty())    
  {    
    return;    
  }    
  else    
  {    
    int top = st.top();    
    st.pop();    
    revprint(st);    
    cout << top << " ";                                                                                                         
  }    
}  

9d98cdf5c9e149ae8a924cf31324b7d1.png使用系统栈 等消栈的时候打印即可

相关文章
|
5月前
|
Linux 数据库 虚拟化
Docker的常见应用部署技巧
以上就是一些Docker的常见应用部署技巧。使用Docker,你可以更容易地部署和管理你的应用,而不需要关心底层的硬件和操作系统。只要你掌握了这些技巧,你就可以更有效地使用Docker来部署你的应用。
122 25
|
11月前
|
存储 JSON Kubernetes
容器日志收集与管理
【10月更文挑战第11天】Kubernetes中的集群级日志处理确保应用程序日志在容器、Pod或节点出现故障时仍可获取。
|
7月前
|
存储 关系型数据库 分布式数据库
PolarDB开源数据库进阶课18 通过pg_bulkload适配pfs实现批量导入提速
本文介绍了如何修改 `pg_bulkload` 工具以适配 PolarDB 的 PFS(Polar File System),从而加速批量导入数据。实验环境依赖于 Docker 容器中的 loop 设备模拟共享存储。通过对 `writer_direct.c` 文件的修改,替换了一些标准文件操作接口为 PFS 对应接口,实现了对 PolarDB 15 版本的支持。测试结果显示,使用 `pg_bulkload` 导入 1000 万条数据的速度是 COPY 命令的三倍多。此外,文章还提供了详细的步骤和代码示例,帮助读者理解和实践这一过程。
247 0
|
机器学习/深度学习 人工智能 自然语言处理
|
10月前
|
人工智能 自然语言处理 搜索推荐
AI辅助教育:个性化学习的新纪元
【10月更文挑战第31天】随着人工智能(AI)技术的发展,教育领域迎来了一场前所未有的变革。AI辅助教育通过智能推荐、语音助手、评估系统和虚拟助教等应用,实现了个性化学习,提升了教学效率。本文探讨了AI如何重塑教育模式,以及个性化学习在新时代教育中的重要性。
『PyQt5-Qt Designer篇』| 07 Qt Designer中栅格布局和表单布局的使用
『PyQt5-Qt Designer篇』| 07 Qt Designer中栅格布局和表单布局的使用
323 0
|
SQL 安全 关系型数据库
使用SQLMap进行SQL注入测试
使用SQLMap进行SQL注入测试
pandas list\dict 转换为DataFrame
pandas list\dict 转换为DataFrame
pandas list\dict 转换为DataFrame
|
JavaScript 前端开发
vue图片预览 90度旋转
vue图片预览 90度旋转
320 0