方法一:递归
定义一个二维数组a[i][j],i表示队列剩余元素个数,j表示栈中元素个数;
当队列中元素为空:
此时只剩栈中元素,我们只能按照顺序依次push出栈,所以此时只有一种情况,返回一;
当队列中元素不为空:
①栈中元素为空,只能进行入栈操作(i-1,j+1)
②栈中元素不为空,可入栈(i-1,j+1),可出栈(i,j-1)
需要注意的是此题还用到记忆化搜索,否则你会收获TLE。
#include <cstdio>
#include <iostream>
using namespace std;
int n;
int a[20][20];//i表示队列剩余元素个数,j表示栈中元素个数;
int dfs(int i, int j) {
if (a[i][j]) return a[i][j];//划重点:记忆化搜索,如果a[i][j]已经有值,就直接返回
if (i == 0) return 1;//队列里没了,只剩栈了,只有一种情况,返回一
if (j > 0) a[i][j] += dfs(i, j - 1);//如果栈里还有元素,可出栈
a[i][j] += dfs(i - 1, j + 1);//不管栈里有没有,都可入栈
return a[i][j];
}
int main()
{
cin >> n;
int ans=dfs(n, 0);
cout << ans;
return 0;
}
方法二:递推/DP
定义一个二维数组a[i][j],i表示总进栈数,j表示总出栈数;
那么,对于a[i][j],它的上一步操作是入栈或者出栈,若入栈(即上一步是a[i-1][j]),若出栈(即上一步是a[i][j-1])
即
和递归同理,我们需要特别判断一下i和j相等的情况,此时栈内为空,上一步操作只能是出栈(即a[i][j-1])
那么边界在哪里呢,和上面的递归同理,当队列中元素为空时,这个时候,只剩栈中的元素啦,只能一个一个出栈啦,只有这一种方法。
好啦,上代码
#include <cstdio>
#include <iostream>
using namespace std;
int n;
int a[20][20];
int main()
{
cin >> n;
for (int i = 0; i <= n; i++) {
a[i][0] = 1;//边界
}
for (int i = 1; i <= n; i++) {//i表示总进栈数,j表示总出栈数
for (int j = 1; j <= i; j++) {//这里一定要注意j的范围,不要和我一样因为j的范围错了,得不出正确答案写了半天(我很菜我知道了)
if (i == j) a[i][j] = a[i][j - 1];//此时栈内为空,上一步操作一定是出栈
else a[i][j] = a[i][j - 1] + a[i - 1][j];//上一步是入栈或者出栈
}
}
int ans = a[n][n];//当入栈数和出栈数都是n时,就可以输出辣
cout << ans;
return 0;
}
方法三:卡特兰数
卡塔兰数是什么,它可以吃吗
不会卡特兰数的看这里
【算法】震惊!!!史上最详细的卡特兰数浅谈!!!_Fighter的博客-CSDN博客_卡特兰数
还有这里算法中的数学---卡特兰数(解析+代码实现)_KI的博客-CSDN博客_c++卡特兰数
不管看哪里,学会就好啊哈哈
然后我们得到了一个式子 f[n]=f[0]∗f[n−1]+f[1]∗f[n−2]+...+f[n−1]∗f[0]
#include <cstdio>
#include <iostream>
using namespace std;
int a[20] = { 1,1 };
int n;
int main()
{
cin >> n;
for (int i = 2; i <= n; i++) {
for (int j = 0; j < i; j++) {
a[i] += a[i - j - 1] * a[j];
}
}
cout << a[n];
return 0;
}