java编程求卡特兰数_从一道动态规划题带你领略『卡特兰数』是如何秒杀算法题的...

一、 leetcode 96 号题

题意:给定一个整数 n,求以 1 … n 为节点组成的二叉搜索树有多少种?

n = 3 时:

37bda150e1bd188134706328cc74f92c.png

二、动态规划

思路:从 1 开始到 n ,每次以这个数为根,左子树存放比它小的数,右子树存放比它大的数。每个根不重复,因此每个树也必定不重复。

左子树和右子树,又可以按照这个规则去生成新的树。

1c04a6c46ed1f1ab5c1bcaa1cdc8f603.png

例如:n = 3的时候

1为根:比 1 小的数只有 0,不用管。比 1 大的数有 2 和 3。

拿 2 和 3 来生成一棵树和拿 1 和 2 来生成一棵树的种数是不是相同的?那么 1 和 2 能生成多少种树呢?

2为根:比 2 小的是 1,比 2 大的是 3。这里只有 1 种。

3为根:比 3 小的是 1 和 2,1 和 2 能生成多少种树呢?

我们先暂停思维,来到一个新的问题。n = 2 的时候,结果应该是多少?

3929d8360ba5861ba919d7a8623888c7.png

n = 2 的时候,按照我们之前的方法。

1 为根:比 1 大的数只有 2, 这里有 1 种。

2 为根:比 2 小的数只有 1, 这里有 1 种。

那答案就应该是 2 种。

解决了 n = 2 的问题,那 n = 3 的问题就也解决了。ans = 2 + 1 + 2 = 5。

我们来看一般情况。输入一个 n 。

定义一个 F(i) 表示以 i 为根,生成的树的种数。

定义一个 G(n) 表示输入 n 的时候,输出的结果。此处一定要注意 F 与 G 的区别。

以 i 为根的时候,能生成多少种树?

比 i 小的有 i - 1 个,比 i 大的有 n - i 个。因此左子树有 i - 1 个, 右子树有 n - i 个数。那么,F(i) = G(i - 1) * G(n - i)。

而我们求的 G(n) = F(1) + F(2) + …… + F(n)。

把两个公式综合 :

747bbe756541d342c2e8ed64958b6ac6.png

d[0] = 1; // 0 的时候特殊处理

for (int i = 1; i <= n; i++)

for (int j = 1; j <= i; j++)

d[i] += d[j-1] * d[i-j];

以上是利用动态规划求解的思路。

时间复杂度:O(n^2)

空间复杂度:O(n)

三、 Catalan公式

这个题目还有一种很强的解法,卡特兰公式。卡特兰公式和排列组合有很大关系,不属于偏难怪解法,有很多算法和数据结构的问题本质上就是卡特兰公式的应用。比如二叉树的形态数,出栈序列数,括号匹配问题等。公式不要紧,没必要去硬背。主要是理解卡特兰问题应用的特征,把问题抽象到已有模型中来。

Catalan 递推项满足:

C(n) = C(0) C(n-1) + C(1) C(n-2) + … + C(n-2) C(1) + C(n-1) C(0)

Catalan 通项公式:

45a1322fb272af60342709dd438887aa.png =

ee8a187a64b937d8716c5cea59453156.png

1b70dc9a94252ab6cd51339faeaff168.png

Catalan 递推公式1:

61786394b2620a4551c67b378060bc71.png =

bb81d40264d4bc95ee5f0cd501dcfbcc.png

fdc627e03d472ce77846774045f9c213.png

Catalan 性质:

c5d71aecf4ba914a66b3d6b89976b336.png =

73c34db04c31b495d948c9a914c762c3.png -

6ea3062948eaf94747609d9aa47202c5.png

这个题目里面,由我们上面的 G(n) 很容易可以看出是一个卡特兰的应用。

我们用它的递推公式来求解。

de83d840247e4504311a2bdcded597fc.png 的值,

8efa373ff5db6179befaf6e442e757c2.png =

1c8f43d57c1fb8f21fe092db871b3ac9.png

bb07243b2774ccf39752d0c5a584b410.png。公式顺推,代码中 n 次循环结束后的 ans 值就是

81e8a7e678c6dcb5c513ed0d9632c57a.png 对应的值。类比斐波那契最简解法。

long ans = 1;

for(int i = 1; i <= n; i++)

ans = ans * 2 * (2 * i + 1) / (i + 2);

return (int) ans;

时间复杂度:O(n)

空间复杂度:O(1)

四、Catalan应用

例题1:括号序列

给 n 对括号,可以合成的合法序列有多少种?

082c6570b230bd4e99fe777547c6f457.png

首先计算一共的序列种数。n 对括号, 一共有 2n 个位置。我们选出其中 n 个位置放放置左括号,剩下的位置肯定就是右括号了。因此一共的种数为:

a72cc898a7d542afd3d388ded636736d.png

接下来找出非法的括号序列数。每个非法的序列,在它的奇数位置,一定存在右括号数量大于左括号的数量。

fd7d6e03f1fd884487ff3d5dc661ad16.png

在上图中:第 2m + 1 的时候,右括号大于左括号,因此该序列非法。

在 2m + 1 前:

右括号数量为:m + 1

左括号数量为:m

在 2m + 1后:

总的数量:n - 2m - 1

左括号有:n - 2m - 1 - (m + 1) = n - m

右括号有:n - 2m - 1 - m = n - m - 1

这个时候我们将右边的左括号和右括号位置置换(总的组合数量不会受到影响)。那么在整个序列 2n 个位置中:

右括号的数量为:m + 1 + n - m = n + 1

左括号的数量为:m + n - m - 1 = n - 1

在长度为 2n 里面有 n + 1 个右括号,数量为:

7f97a2e469ab3a1d64017a84e45c4ed0.png 。你也可以理解从左括号的角度去看:

d300a38fb856d7a0803d3565d6ad3430.png

在上面两个步骤以后,我们得到的合法序列数:

866b40e76b3c18843bba8ff5a25e1615.png -

d3b281a1529c62265d332dd32d4c272b.png 。这就是 Catalan 公式的性质公式。知道是 Catalan,我们就可以用刚刚的方法求解问题的答案。

例题2 :一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?

例题3 :给出一个n,要求一个长度为2n的01序列,使得序列的任意前缀中1的个数不少于0的个数, 有多少个不同的01序列?

例题4 :2n个人要买票价为五元的电影票,每人只买一张,但是售票员没有钱找零。其中,n个人持有五元,另外n个人持有十元,问在不发生找零困难的情况下,有多少种排队方法?(阿里有个笔试题根据这个变化的)

其他动态规划算法题推荐:

1、告别动态规划,连刷40道动规算法题,我总结了动规的套路

2、动态规划该如何优化?我总结了这些套路,以后优化就是分分钟

3、算法专题(动规):不同的定义产生不同的解法

4、详解三道一维的动态规划算法题

5、经典动态规划:高楼扔鸡蛋

6、详解 leetcode 221 题:最大正方形

7、动态规划之正则表达式

推荐阅读

写了很久,这是一份适合普通大众/科班/非科班的『学习路线』

有必要说一说即将到来的春招(经历+重要性+如何准备)

普普通通,我的三年大学

历经两个月,我的秋招之路结束了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值