算法题目 -- 不同的二叉搜索树

125 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情

不同的二叉搜索树

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。通俗来讲,就是返回n个节点的二叉树有几种形状

解析

n = 1时,我们可以很明显的知道,二叉树的形状只有一种。

n = 2时,我们依然可以明显的知道,二叉树的形状只有两种。

图片.png

n = 3时,情况就稍微复杂点,但是通过我聪明的小脑依然可以把每种情况都画出来。 图片.png

聪明的小伙伴可能发现了,n=3时,它的根节点的左子树和右子树不就是由n={0,1,2}的二叉树拼凑起来的嘛? 按照图片顺序可知每个n=3二叉树的拼凑方式:

  1. left:n=0 right:n=2
  2. left:n=0 right:n=2
  3. left:n=1 right:n=1
  4. ....

不难发现,就是将每种比n小的二叉树当作左右子树(左右子树节点数的和等于n-1,减1是因为不计算根节点),并将左右子树的笛卡尔积相加就能得到最终结果。发现规律后,我们可以用动态规划来解决这道题。

设计数组record[]来记录n个节点的二叉树有多少种形状。通过动态规划的原理从n=1开始不断向后求出结果,直到n=n,最后返回结果即可。

这题限制了n的范围(1~19),我们先计算出来每个结果,通过打表也是可行的,但最后发现因为计算简单,且n的范围较小,两者的效率和速度相差不大。

代码

class Solution {
    public int numTrees(int n) {
        int[] record = new int[n + 1];
        //初始化
        record[0] = 1;
        for(int i = 1; i <= n;i++){
            for(int j = 0; j < i; j++){
                record[i] += record[j] * record[i-j-1];
            }
        }
        return record[n];
    }
}

打表的代码

class Solution {
    int[] record = new int[]{1,1,2,5,14,42,132,429,1430,4862,16796,58786,208012,742900,2674440,9694845,35357670,129644790,477638700,1767263190};
    public int numTrees(int n) {
        return record[n];
    }
}