算法笔记练习 题解合集
题目
题目描述
栈是常用的一种数据结构,有n令元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。你已经知道栈的操作有两•种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。
输入
一个整数n(1<=n<=15)
输出
一个整数,即可能输出序列的总数目。
样例输入
3
样例输出
5
思路
DFS版本
void DFS(int wait, int stack);
DFS
只需要两个形参来记录状态:
- 目前等待入栈的元素数量
wait
; - 目前栈内元素数量
stack
;
递归边界:
wait
和stack
同时等于 0 的时候,已经产生了一个合法输出,记录并返回。
递归调用:
- 若还有正在等待的元素(
wait > 0
),可以令其入栈; - 若栈非空(
stack > 0
),可以令其出栈。
卡特兰数版本
其实读完题第一个想到的思路是直接算卡特兰数。若有
n
n
n 个元素等待入栈,合法的出栈序列数量就是卡特兰数:
1
n
+
1
C
2
n
n
\frac1{n+1}C_{2n}^n
n+11C2nn
如何计算组合数
C
2
n
n
C_{2n}^n
C2nn 又是另一个话题了,可以参考算法笔记 5.8 组合数。
代码
DFS版本
#include <iostream>
using namespace std;
int ans = 0;
void DFS(int wait, int stack) {
if (wait == 0 && stack == 0) {
++ans;
return;
}
if (wait > 0)
DFS(wait - 1, stack + 1);
if (stack > 0)
DFS(wait, stack - 1);
}
int main() {
int n, stack;
while (scanf("%d", &n) != EOF) {
ans = 0;
DFS(n, 0);
printf("%d\n", ans);
}
return 0;
}
卡特兰数版本
#include <iostream>
using namespace std;
int main() {
long long n;
while (scanf("%ld", &n) != EOF) {
long long ans = 1;
for (long long i = 1; i <= n; ++i)
ans = ans * (n + i) / i;
printf("%ld\n", ans / (n + 1));
}
return 0;
}