加载中...

daily leetcode - unique-binary-search-trees - !

题目地址

https://leetcode.com/problems/unique-binary-search-trees/

题目描述

Given n , how many structurally unique BST's (binary search trees) that store values 1 ... n?

Example:

Input: 3
Output: 5
Explanation:
Given _n_ = 3, there are a total of 5 unique BST's:

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

思路

这道题实际上是 卡塔兰数 Catalan Numbe 的一个例子,如果对卡塔兰数不熟悉的童鞋可能真不太好做。话说其实我也是今天才知道的好嘛 -.-|||,为啥我以前都不知道捏?!为啥卡塔兰数不像斐波那契数那样人尽皆知呢,是我太孤陋寡闻么?!不过今天知道也不晚,不断的学习新的东西,这才是刷题的意义所在嘛! 好了,废话不多说了,赶紧回到题目上来吧。我们先来看当 n = 1 的情况,只能形成唯一的一棵二叉搜索树,n 分别为 1,2,3 的情况如下所示:

                    1                        n = 1

                2        1                   n = 2
               /          \
              1            2
  
   1         3     3      2      1           n = 3
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

就跟斐波那契数列一样,我们把 n = 0 时赋为 1,因为空树也算一种二叉搜索树,那么 n = 1 时的情况可以看做是其左子树个数乘以右子树的个数,左右子树都是空树,所以 1 乘 1 还是 1。那么 n = 2 时,由于 1 和 2 都可以为根,分别算出来,再把它们加起来即可。n = 2 的情况可由下面式子算出(这里的 dp[i] 表示当有 i 个数字能组成的 BST 的个数):

dp[2] = dp[0] * dp[1]   (1 为根的情况,则左子树一定不存在,右子树可以有一个数字)

    + dp[1] * dp[0]   (2 为根的情况,则左子树可以有一个数字,右子树一定不存在)

同理可写出 n = 3 的计算方法:

dp[3] = dp[0] * dp[2]   (1 为根的情况,则左子树一定不存在,右子树可以有两个数字)

    + dp[1] * dp[1]   (2 为根的情况,则左右子树都可以各有一个数字)

    + dp[2] * dp[0]   (3 为根的情况,则左子树可以有两个数字,右子树一定不存在)

由此可以得出卡塔兰数列的递推式为:

C_0 = 1 \quad \mbox{and} \quad C_{n+1}=\sum_{i=0}^{n}C_i,C_{n-i}\quad\mbox{for }n\ge 0.

关键点解析

代码

解法一:

class Solution {
public:
    int numTrees(int n) {
        vector<int> dp(n + 1);
        dp[0] = dp[1] = 1;
        for (int i = 2; i <= n; ++i) {
            for (int j = 0; j < i; ++j) {
                dp[i] += dp[j] * dp[i - j - 1];
            }
        }
        return dp[n];
    }
};

由卡特兰数的递推式还可以推导出其通项公式,即 C(2n,n)/(n+1),表示在 2n 个数字中任取 n 个数的方法再除以 n+1,只要你还没有忘记高中的排列组合的知识,就不难写出下面的代码,注意在相乘的时候为了防止整型数溢出,要将结果 res 定义为长整型,参见代码如下:

解法二:

class Solution {
public:
    int numTrees(int n) {
        long res = 1;
        for (int i = n + 1; i <= 2 * n; ++i) {
            res = res * i / (i - n);
        }
        return res / (n + 1);
    }
};

本文参考自:
https://github.com/grandyang/leetcode/ &
https://github.com/azl397985856/leetcode


标题: daily leetcode - unique-binary-search-trees - !
文章作者: lonuslan
文章链接: https://www.lonuslan.com/articles/2020/04/19/1587263275876.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hi I'm LonusLan 👋🏼

评论