已知\(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个数的入栈序列,求一共有多少种出栈序列 (卡特兰数)的更多相关文章

  1. n个元素的入栈顺序有多少种出栈顺序?

    问题:w1.w2.w3.w4.w5,5个元素将会按顺序入栈,求出栈顺序有多少种情况. 先写一下结论方便记忆: 1个元素:1种 2个元素:2种 3个元素:5种 4个元素:14种 5个元素:42种 简单的 ...

  2. 找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数

    找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数 #include<iostream>using namespace s ...

  3. 求入栈顺序为1234……N的序列的所有可能的出栈序列

    class Program { private static void Fun(int x, int n, Stack<int> stack, List<int> outLis ...

  4. 已知ip地址和其子网掩码如何求网络号子网号主机号

    已知ip地址为10.130.89.95,其子网掩码为255.255.255.224,求其网络号.子网号和主机号. 要看子网掩码变长在第几节,255.255.255.224是在第四节借了位 把224转换 ...

  5. 已知空间三点组成的面求该面上某点的Z值

    已知空间三点,那么可以就可以确定空间三点组成的平面.此时可以根据某一点的X值和Y值,来求取该点在平面上的Z值.这个过程对于求三角面片上某点的高程或者权值特别有用,其本身也可以看作一种线性插值. 其算法 ...

  6. DS Tree 已知先序、中序 => 建树 => 求后序

    参考:二叉树--前序和中序得到后序 思路历程: 在最初敲的时候,经常会弄混preorder和midorder的元素位置.大体的思路就是在preorder中找到根节点(根节点在序列的左边),然后在mid ...

  7. poj 1363 Rails in PopPush City &&【求堆栈中合法出栈顺序次数】

    问题如下: 问题 B: Rails 时间限制: Sec 内存限制: MB 提交: 解决: [提交][状态][讨论版] 题目描述 There is a famous railway station in ...

  8. n个元素进栈,共有多少种出栈顺序?

    1.基于栈的问题分析 我们把n个元素的出栈个数的记为f(n), 那么对于1,2,3, 我们很容易得出:                                   f(1) = 1     / ...

  9. c语言将2进制数转化为10进制数(栈的初始化,进栈,出栈)

    //c语言描述 将2进制转化为10进制 #include <stdio.h> #include <stdlib.h> #include <math.h> #defi ...

  10. 已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数

    #include<iostream> using namespace std; //#define maxn 2000010 #include<stdio.h> //int a ...

随机推荐

  1. 对表单input输入框加特殊符号(正斜杠和反斜杠)校验

    <p>图片名称:</p><input type="text" name="afterName" style="heigh ...

  2. jmeter-脚本制作

    HTTP请求 默认端口号 HTTP默认端口号:80 HTTPS默认端口:443 数据来源 通过网络抓包软件(Fiddler.Charles等).接口文档数据 脚本制作+结果 录制脚本 badbod 录 ...

  3. 查看shell 用户连接数

    w | grep pts |wc -l

  4. 视频播放-videojs

    视频播放-video-js组件 安装 yarn add video.js --save npm install video.js --save 代码 import React, { useEffect ...

  5. week3题解

    1.寄包柜 看到题目最容易想到开二位数组 但数据量过大,因此需要map #include <bits/stdc++.h> using namespace std; map<int,m ...

  6. Shell脚本之while read line的用法

    Shell脚本之while read line的用法 while read line do - done < file read通过输入重定向,把file的第一行所有的内容赋值给变量line,循 ...

  7. 微软NewBing真是Niubility

    这是本人2012年的拙作:           晨兮,闻风雨,后而雷鸣电闪.迟不可再三,若故无食.然何如耶?雨大风狂,单车奈何?公交卡空,恐时不予我也.不免叹也,天亦不予我!         而后出, ...

  8. Activiti7开发(一)

    0.前言 开发背景 项目开发设计审批工作流,企业微信的审批不错,但是下拉列表不支持后期添加,所以只能自己实现,通过gitee查找相关工作流的开源项目,参考有 闲鹿(RuoYi+Activiti6) h ...

  9. 19.new和delete用于数组

    程序1: //2022年9月20日22:06:27 #include <iostream> #pragma warning(disable:4996) using namespace st ...

  10. Z 函数

    简单记一下,避免忘记. z 函数 对于字符串 \(S\),我们将 \(z(i)\) 定义为从 \(i\) 开始的后缀与 \(S\) 的最长公共前缀的长度. \(O(n)\) 求出 z 函数 我们添加一 ...