已知n个数的入栈序列,求一共有多少种出栈序列 (卡特兰数)
已知\(n\)个数的入栈序列,求一共有多少种出栈序列
这个经典问题有两种解法。
解法一:
设\(f(x)\)为\(x\)个数入栈后,再全部出栈的序列数量
假设我们有\(4\)个数\(a,b,c,d\), 我们来看\(a\)的出栈顺序.
假如\(a\)第一个出栈,那么后面还有\(3\)个数没有出栈,因此方法数是\(f(3)\).
假设\(a\)第二个出栈,那么\(a\)的前面有\(1\)个数已经出栈,后面还有\(2\)个数没有出栈,因此方法数为\(f(1) * f(2)\).
假设\(a\)第三个出栈,那么\(a\)的前面有\(2\)个数已经出栈,后面还有\(1\)个数没有出栈,因此方法数为\(f(2) * f(1)\).
同理,\(a\)第四个出栈的方法数为\(f(3)\).
那么我们就可以得到\(f(4) = f(3) + f(1) *f(2) + f(2)*f(1) +f(3)\).
对于\(n\)来推广一下,可以得到:\(f(n)=\sum_{i=1}^{n}f(i - 1)*f(n-i)\).
不难发现这就是卡特兰数,这里就不在赘述了。
解法二:
我们假设\(-1\)表示出栈,\(1\)表示入栈,这样我们就可以用\(-1\)和\(1\)组成的序列来表示出入栈操作。
首先来限定一些条件,一个合法的序列\(0\)和\(1\)的数量一定是相等的。并且序列的前缀和一定是不小于\(0\)的。
了解了上面两个条件后,我们知道所有的序列数为\(C^{\ n}_{2n}\),因为\(-1\)和\(1\)的数量相同。在这\(C^{\ n}_{2n}\)个序列中,存在不合法的序列,即前缀和小于\(0\)的序列,我们想要知道这些不合法的序列有多少。
假设我们有一个序列\(1,-1,-1,1,-1,1\),这里在第三个下标,我们发现了它的前缀和小于\(0\),因此它不合法。再来推广一下,在这所有\(C^{\ n}_{2n}\)个序列中,不合法的序列它的前缀和一定在某一处小于\(0\).
接下来,我们将序列开头到不合法下标的这一段进行取反。首先拿上面的例子来进行说明,取反后得到:\(-1,1,1,1,-1,1\),不难发现,现在得到的序列\(+1\)比\(-1\)多出一个.
现在再来进行推广,我们截取的不合法序列段(从开头到不合法前缀和下标),这一段中的\(-1\)一定比\(+1\)多一个,那么将这一段取反后所得到的总序列中的\(+1\)一定比\(-1\)多一个。
不难发现,不合法的序列一定对应唯一一个取反后的序列,并且取反后的序列中\(+1\)有\(n+1\)个,\(-1\)有\(n-1\)个,那么根据这个条件,我们就可以得到所有不合法的序列数量为\(C_{2n}^{n+1}\)或者\(C^{n-1}_{2n}\)(因为他两相等)。
最后,合法的序列数为:\(C^{\ n}_{2n}-C_{2n}^{n+1\ or\ n-1}\).
这个解法的关键在于,不合法的序列一定唯一对应一个取反后的序列,那么我们可以算出所有取反后的数列有多少种(根据\(+1\)有\(n+1\)个,\(-1\)有\(n-1\)个的性质),来对应出不合法的序列数,从而得到答案.
因为感觉这种解法非常的巧妙,因此想写篇博客来总结一下.
已知n个数的入栈序列,求一共有多少种出栈序列 (卡特兰数)的更多相关文章
- n个元素的入栈顺序有多少种出栈顺序?
问题:w1.w2.w3.w4.w5,5个元素将会按顺序入栈,求出栈顺序有多少种情况. 先写一下结论方便记忆: 1个元素:1种 2个元素:2种 3个元素:5种 4个元素:14种 5个元素:42种 简单的 ...
- 找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数 #include<iostream>using namespace s ...
- 求入栈顺序为1234……N的序列的所有可能的出栈序列
class Program { private static void Fun(int x, int n, Stack<int> stack, List<int> outLis ...
- 已知ip地址和其子网掩码如何求网络号子网号主机号
已知ip地址为10.130.89.95,其子网掩码为255.255.255.224,求其网络号.子网号和主机号. 要看子网掩码变长在第几节,255.255.255.224是在第四节借了位 把224转换 ...
- 已知空间三点组成的面求该面上某点的Z值
已知空间三点,那么可以就可以确定空间三点组成的平面.此时可以根据某一点的X值和Y值,来求取该点在平面上的Z值.这个过程对于求三角面片上某点的高程或者权值特别有用,其本身也可以看作一种线性插值. 其算法 ...
- DS Tree 已知先序、中序 => 建树 => 求后序
参考:二叉树--前序和中序得到后序 思路历程: 在最初敲的时候,经常会弄混preorder和midorder的元素位置.大体的思路就是在preorder中找到根节点(根节点在序列的左边),然后在mid ...
- poj 1363 Rails in PopPush City &&【求堆栈中合法出栈顺序次数】
问题如下: 问题 B: Rails 时间限制: Sec 内存限制: MB 提交: 解决: [提交][状态][讨论版] 题目描述 There is a famous railway station in ...
- n个元素进栈,共有多少种出栈顺序?
1.基于栈的问题分析 我们把n个元素的出栈个数的记为f(n), 那么对于1,2,3, 我们很容易得出: f(1) = 1 / ...
- c语言将2进制数转化为10进制数(栈的初始化,进栈,出栈)
//c语言描述 将2进制转化为10进制 #include <stdio.h> #include <stdlib.h> #include <math.h> #defi ...
- 已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
#include<iostream> using namespace std; //#define maxn 2000010 #include<stdio.h> //int a ...
随机推荐
- Java包机制与文档注释
Java包机制与文档注释 包机制 为了更好地组织类,java提供包机制,用于区分类名的命名空间 包语句的语法: package pkg1.pkg2.pkg3...; // 必须在文件第一行 一般用公司 ...
- shell编程【一】
参考网址:[Linux命令大全][]:https://linux265.com/course/linux-commands.html 为什么要学习shell指令? 学习shell指令的本身也是在了解L ...
- 配置git到码云
一.安装完git之后,对项目文件点击右键选择Git Base Here #Git 全局设置用户名与邮箱 git config --global user.name "" git c ...
- dotNetCore创建Windows服务程序并安装服务
一.创建控制台程序 二.在项目中添加新建项,选择Windows服务类型. 此时会出现一个错误提示,这是因为尚未添加windows服务控制引用造成的. 三.添加Nuget包,System.Service ...
- git 拉取远端别的分支的代码,并创建本地分支
创建本地分支 new_dev, 并且拉取远端new_dev的代码到本地new_devgit checkout -b new_dev origin/new_dev
- ArrayList学习
核心源码 package java.util; import java.util.function.Consumer; import java.util.function.Predicate; imp ...
- verilog 概念版
一.MCU芯片的定义 MCU芯片是指微控制单元(MicrocontrollerUnit:MCU),又称单片微型计算机或者单片机,是把中央处理器的频率与规格做适当缩减,并将内存.计数器.USB.A/D转 ...
- mysql替换空格制表符换行
update ztbdb_pro set pro=REPLACE(pro,CHAR(10),''); update ztbdb_pro set pro=REPLACE(pro,CHAR(13),'') ...
- Python学习笔记--PySpark的相关基础学习(一)
PySpark包的下载 下载PySpark第三方包: 构建PySpark的执行环境入口对象 PySpark的编程模型 数据输入 对于SparkContext对象里面的成员方法parallelize,支 ...
- jetbrains账户的注册
注册步骤 1.进入官网界面 官网地址在这里啦:https://www.jetbrains.com/ 官网本来显示的是这个界面: 点击右上角的Learning Tools,然后选择该页面内的这里: 2. ...