本文的读者应该具有程序设计的基础,且已经编写过一些递归题目的代码。

(一) 前言

递归是算法领域最重要的基础算法之一,在后续的动态规划算法、搜索算法中也会经常用到递归思想。

递归算法常用于以下三种场景:
(1)递归定义的数学函数(阶乘、阿克曼函数等)
(2)具有递归特性的数据结构(树,二叉树,堆等)
(3)其他可用递归求解的问题
        通常用F函数表示递归,例如F(n)表示一个数据规模为n的递归函数。递归算法的思想就是思考如何用问题规模小于n的递归函数,如F(n-1)、F(n/2)等,设计算法求得F(n)。

和学习其他算法一样,递归思想的培养既要一定量的训练,也要思考。学习者应该先学习并掌握一些和递归密切相关的方法(基础性递归问题,以及递归实现指数枚举,组合、排列等)和数学概念(斐波那契,卡特兰数),再通过训练、思考,总结来逐步掌握递归算法和思想。本文仅从递归的角度,对卡特兰数及其相关问题进行一些基础性介绍。

(二) 什么是卡特兰数

        卡特兰数(英语:Catalan number),又称卡塔兰数明安图数,是组合数学中一种常出现于各种计数问题中的数列。以比利时的数学家欧仁·查理·卡特兰的名字来命名。卡特兰数前几项为(从第0项开始):1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...(编程时尽量用long long类型)

(三) 卡特兰数对应的递归问题

在数据结构与算法领域,相当多的问题与卡特兰数相关。典型的有:n元素的出栈序列问题、二叉树的形态问题、凸多边形的三角划分问题(有代码)、括号匹配方案问题等。

(1)n元素出栈序列问题

题目:1,2,3......n个元素按次序依次进栈,请问共有多少种出栈序列方案。例如n=3时,答案是5,出栈序列分别是123,132,213,231,321。

解法:用递归思想,如何将F(n)问题变小?思考最后一个出栈元素,观察发现其值可能是1....n任意一个,假定最后一个出栈元素是i,那么1,2....i-1在i入栈之前一定已经出栈(不然i不会是最后一个),i入栈后,i+1,i+2......n依次入栈。注意:i前面入栈元素的出栈序列i之后入栈元素的出栈序列没有任何关联和影响,因此:

        以i为最后一个元素的出栈序列方案数=前i-1个的方案数 * 后n-i个的方案数。

i可以是1....n任何一个,由此得到计算n个元素出栈序列的递归计算公式(卡特兰公式):

F(n)=F(0)∗F(n−1)+F(1)∗F(n−2)+F(2)∗F(n−3)+...+F(n−1)∗F(0)

(2)n个点二叉树的形态问题

题目:n个结点的二叉树,有多少种不同的形态?

解法:二叉树分为三部分,树根,左子树,右子树,其中左右子树可以为空。设n个点二叉树形态为F(n),那么拿出一个点作为树根,此时有n-1个点可以分给左右子树,分配方案共有n种:分别是左0右n-1,左1右n-2.........左n-1右0。由于左右子树形态并无关联和影响,因此左子树分配i个结点,右子树分配n-1-i个结点的方案数为F(i)*F(n-1-i)。

总的方案数为: F(n)=F(0)∗F(n−1)+F(1)∗F(n−2)+F(2)∗F(n−3)+...+F(n−1)∗F(0)

OJ题目:11082 完全二叉树的种类,n个叶子结点的完全二叉树,其形态有多少种?(完全二叉树意味着每个分支结点都有2个儿子结点)

解法:n个叶子被分配给左右子树,注意子树不能有0个叶子。因为分配方案为左1右n-1,左2右n-2.........

总方案数为: F(n)=F(1)∗F(n−1)+F(2)∗F(n−2)+F(3)∗F(n−3)+...+F(n−1)∗F(1)

这个公式和上面略有不同,思考把F()函数每一项都减一,实际上这个公式得到的结果是标准卡特兰的F(n-1)算式。

(3)凸多边形的三角划分问题-10343 划分凸多边形

题目:一个正凸N边形,用N-3条互不相交的对角线将正N边形分成N-2个三角形的划分方案数。

解法:给结点进行编号1至N,为了降低问题规模,先将1号和其他点连接(不能连2和N),共有N-3种连接方案,假定1号和结点i进行连线,此时凸N边形被划分成两部分,一边是一个凸i边形(结点1....i),另一个是一个凸N-i边形(结点i+1.....n),这两部分的划分是独立的。因此当结点1和i连线时,划分方案数=F(i)*F(n-i)。

总方案数为: F(n)=F(3)∗F(n−3)+F(4)∗F(n−4)+F(5)∗F(n−5)+...+F(n−3)∗F(3)

这里计算时F(3)=1,三角形就一种划分方案,这个F(3)其实和和标准卡特兰的F(1)一样,F(4)=2,四边形有两种划分方案。因此此题目F(n)相当于标准卡特兰的F(n-2)。

计算卡特兰数时有两个点需要注意,第一,卡特兰上升速度极快,因此尽量用longlong类型存储,第二,递归思想可以,但递归算法效率较差,用递推替换递归,降低复杂度。

#include <iostream>
using namespace std;
int main()
{int i,j,n;long long f[25]={0};cin>>n;if(n<3)//不满足多边形划分条件{cout<<"No answer";return 0;}f[0]=f[1]=1;//卡特兰前两项for(i=2;i<=n-2;i++){for(j=0;j<i;j++)f[i]+=f[j]*f[i-j-1];}cout<<f[n-2];//凸多边形问题需要-2return 0;
}

(4)括号匹配问题

题目:由  N个“(”和 N 个“)”组成的字符串,要求左括号和右括号是匹配的。例如“)(())(”和“())(()”都是不匹配的括号串。当N=3时,有以下5种匹配的括号串:

解法:只关注第一个字符左括号,其匹配对象位置只能是偶数项位置(自行思考),那么这个右括号可能放在最后一个字符(2*N位置),倒数第二个偶数位(2*(N-1)),依次2*(N-2).......,2。和前面几个例子类似,第一个括号和其匹配括号会将序列分割成两段,当第一个左括号与2*i位置右括号匹配时,序列左段长度为2*(i-1),右段长度为2*(n-i),两段分割方案相互独立。

总方案数为: F(2n)=F(0)∗F(2n−2)+F(2)∗F(2n−4)+F(4)∗F(2n−6)+...+F(2n−2)

最后一项为第一个左括号和最后一个右括号匹配,问题转换为F(2n−2),当然,上述方程实际上就是标注的卡特兰数方案。

括号匹配问题的几个拓展:

11085 买票找零  (50元看成左括号,100元看成右括号)

10344 矩阵连乘积的加括号方式数  (N个矩阵对应N对括号)

17083 多重幂计数问题   (和上题一样)

教材课后习题   2-10 标准二维表问题

上图为转载,原图地址为卡特兰数(Catalan number)(一) - 知乎,有兴趣同学可看,里面还有几个例子。

(四) 结语

少说多做,少讲多练~~!

算法设计与分析-递归与卡特兰数相关推荐

  1. 算法设计与分析——递归与分治策略——全排列

    算法设计与分析--递归与分治策略--全排列 全排列问题的解决是通过分治与递归思想来解决的 首先判断是否递归到了最后一位,如果递归到了最后一位,则输出他当前的全排列序列. 如果没有到达最后一位,则循环的 ...

  2. 算法设计与分析——递归与分治策略——最接近点对问题

    [问题描述] 最近对问题要求在包含有n个点的集合S中,找出距离最近的两个点.设 p1(x1,y1),p2(x2,y2),--,pn(xn,yn)是平面的n个点. 严格地将,最近点对可能不止一对,此例输 ...

  3. 算法设计与分析——递归与分治策略——线性时间选择

    顾名思义:这篇文章讲解的就是如果用线性时间算法来作出元素选择问题. 问题描述:给定线性序集中n个元素和一个整数k,1<=k<=n.要求找出这n个元素中第k小的元素,即如果将这个n个元素依其 ...

  4. 算法设计与分析——递归与分治策略——循环日程赛

    问题描述: 非递归方案一:代码 #include<bits/stdc++.h> using namespace std;void gameTable(vector<vector< ...

  5. 算法设计与分析——递归与分治策略——棋盘覆盖

    问题描述 棋盘覆盖问题要求在2^k * 2^k 个方格组成的棋盘中,你给定任意一个特殊点,用一种方案实现对除该特殊点的棋盘实现全覆盖. 建立模型如图: 解决方案就是利用分治法,将方形棋盘分成4部分,如 ...

  6. 算法设计与分析——递归与分治策略——快速排序

    快速排序--递归算法 处理i,j的先后顺序不能改变 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达 ...

  7. 算法设计与分析——递归与分治——归并排序

    归并排序采用的是一种分治的思想,如下图,先将要排序的元素分为两块,每个块又开始分裂,然后逐个按照特定顺序合并,合成最后我们需要的数组. 归并排序的复杂度: 时间复杂度:O(nlogn) 空间复杂度:O ...

  8. 计算机算法设计与分析 递归实现快速排序和随机化实现快速排序

    递归实现快速排序 主要在于哨兵的选择和分部分进行排序,每次递归将左右两部分分开进行排序,选取子数列的第一个元素作为哨兵,后面按照方法排序即可. #include<bits/stdc++.h> ...

  9. 计算机算法设计与分析 递归实现归并排序和非递归实现归并排序

    递归实现归并排序 输入排序的数组的长度,程序用随机数生成对应的数组,之后递归调用排序,排序过程中思想类似于二分,当每个最小分组中只有一个元素时开始返回,直到排完整个数组. #include<bi ...

  10. 算法设计与分析递归概念之阶乘函数

    阶乘函数可递归地定义为: 其中: n=0 时,n!=1为边界条件 n>0 时,n!=n(n-1)!为递归方程 边界条件与递归方程是递归函数的二个要素,递归函数只有具备了这两个要素,才能在有限次计 ...

最新文章

  1. Linux下实现多网卡绑定
  2. linux关于文件夹的知识,Ubuntu 7.10 系统文件夹相关知识
  3. CCDP-思科认证网络设计高级工程师
  4. QT 多屏参数获取和设置
  5. 6月26号.NET面试题(程序题部分)只要做懂这3道题肯定能脱离菜鸟称号!
  6. 在NVIDIA Jetson TX2上安装TensorFlow
  7. ICE专题:实战分布式的Hello Word 【原创】
  8. 几个查询优化小技巧,可以大大提高效率并解决一些问题
  9. 绘图之使用工作空间直接绘图
  10. vue小案例一:todolist
  11. 二叉树遍历(前中后序遍历代码及注释)
  12. 公众号写作排版指南v2.0(适配Dark Mode)
  13. DVD to MP4视频格式转换器v3.1.0 中文版
  14. I.MX6Q(TQIMX6Q/TQE9)学习笔记——新版BSP之根文件系统挂载
  15. 工具善其事,必先被苦逼的其器所钝伤然后打磨之才能利其器
  16. 【面试问题】进程和线程的区别——通俗易懂
  17. 傅里叶变换的通俗理解
  18. 后序线索化二叉树及遍历(图解)
  19. Swift学习笔记(四)
  20. python 将图片中的颜色进行替换

热门文章

  1. 我的世界java追踪光影_探索MC的光线追踪 真实光影下的马赛克世界
  2. 2021年12月全国程序员薪资出炉,你的排哪里……
  3. 拼音表大全图_阿波罗 STM32F767 开发板资料连载第五十九章 T9 拼音输入法实验
  4. 《前沿科技·吴军讲5G》思维导图详细解析
  5. Python3图片中竖排文字
  6. 计算机切换用户屏幕闪,小编教您Win10切换用户后闪屏的具体办法
  7. nova computer对instance的shut off
  8. 中国裁判文书网(2020最新版)
  9. 有刷直流电机和无刷直流电机有什么区别?
  10. win7如何进入修复计算机,win7电脑故障怎么进入安全模式修复