1. 题目

2. 解答

以 \(1, 2, \cdots, n\) 构建二叉搜索树,其中,任意数字都可以作为根节点来构建二叉搜索树。当我们将某一个数字作为根节点后,其左边数据将构建为左子树,右边数据将构建为右子树。因此,这是一个递归问题。

若以第 \(i\) 个数据为根节点,其左边数据有 \(i-1\) 个,左子树可能情况为 left_num,右边数据有 \(n-i\) 个,右子树可能情况为 right_num,因此以当前数据为根节点可以构建出 left_num * right_num 个二叉搜索树。

所以,我们要做的就是遍历 \(i = 1\cdots n\),统计出每个数据作为根节点可以构建出的二叉搜索树总个数即可。

  • 递归法
class Solution {
public: int numTrees(int n) { int sum = 0; if (n <= 1) return 1; // 以当前的数为根节点,左右两边的数分别构建子树
for (int i = 1; i <= n; i++)
{
int left_num = numTrees(i - 1); // 左边的数可以构建多少个二叉搜索树 int right_num = numTrees(n - i); // 右边的数可以构建多少个二叉搜索树 sum += left_num * right_num;
} return sum;
}
};

但是上面的程序运行时超时了,其实我们只需要统计一半数据就可以了,因为两边是对称的。

比如我们有 1,2,3,4,5 五个数,以 2 作为根节点,左边有 1 个数,右边有 3 个数。以 4 作为根节点,左边有 3 个数,右边有 1 个数。这两种情况是一样的,因此如果数据个数为偶数,我们只需要统计一半数据即可,而为奇数的话我们就要再多统计一个中间数据。

class Solution {
public: int numTrees(int n) { int sum = 0; if (n <= 1) return 1; int is_odd = n % 2;
int mid = n / 2; // 以当前的数为根节点,左右两边的数分别构建子树
for (int i = 1; i <= mid; i++)
{
int left_num = numTrees(i - 1); // 左边的数可以构建多少个二叉搜索树 int right_num = numTrees(n - i); // 右边的数可以构建多少个二叉搜索树 sum += left_num * right_num;
} sum = sum * 2; if (is_odd) sum = sum + numTrees(mid) * numTrees(n - mid - 1); return sum;
}
};

此外,我们还可以定义一个全局变量,来存放已经计算过的数值,避免在递归过程中大量地重复计算。

class Solution {
public: #define MAX 1000 int nums[MAX]; // 存放已经计算过的数值 int numTrees(int n) { int sum = 0; //if (n <= 0) return 1;
if (n <= 1) return 1; // 以当前的数为根节点,左右两边的数分别构建子树
for (int i = 1; i <= n; i++)
{
if (nums[i-1] == 0) nums[i-1] = numTrees(i - 1); // 左边的数可以构建多少个二叉搜索树
int left_num = nums[i-1]; if (nums[n-i] == 0) nums[n-i] = numTrees(n - i); // 右边的数可以构建多少个二叉搜索树
int right_num = nums[n-i]; sum += left_num * right_num;
} return sum;
}
};
  • 迭代法

    还可以将递归改写为循环,避免函数多次调用执行效率较低。
class Solution {
public: int numTrees(int n) { int nums[n+1] = {0}; nums[0] = 1;
nums[1] = 1; if (n <= 1) return 1; for (int i = 2; i <= n; i++)
{
// 从 n=2 开始统计可以构建多少个不同的二叉搜索树
for (int j = 1; j <= i; j++)
{
nums[i] += nums[j-1] * nums[i-j];
}
} return nums[n];
}
};

获取更多精彩,请关注「seniusen」!

LeetCode 96——不同的二叉搜索树的更多相关文章

  1. Java实现 LeetCode 96 不同的二叉搜索树

    96. 不同的二叉搜索树 给定一个整数 n,求以 1 - n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 ...

  2. Leetcode 96. 不同的二叉搜索树

    题目链接 https://leetcode.com/problems/unique-binary-search-trees/description/ 题目描述 给定一个整数 n,求以 1 ... n ...

  3. [LeetCode]96. 不同的二叉搜索树(DP,卡特兰数)

    题目 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 1 \ ...

  4. LeetCode 96. 不同的二叉搜索树(Unique Binary Search Trees )

    题目描述 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 输出: 解释: 给定 n = , 一共有 种不同结构的二叉搜索树: \ / / / \ \ / / ...

  5. LeetCode 96 - 不同的二叉搜索树 - [DP]

    假定 $f[n]$ 表示有 $n$ 个节点的二叉树,有多少种不同结构. 因此 $f[n] = \sum_{i=0}^{n-1} (f[i] \times f[n-1-i])$,选一个节点作为根节点,那 ...

  6. Leetcode:96. 不同的二叉搜索树

    Leetcode:96. 不同的二叉搜索树 Leetcode:96. 不同的二叉搜索树 题目在链接中,点进去看看吧! 先介绍一个名词:卡特兰数 卡特兰数 卡特兰数Cn满足以下递推关系: \[ C_{n ...

  7. 【JavaScript】Leetcode每日一题-二叉搜索树的范围和

    [JavaScript]Leetcode每日一题-二叉搜索树的范围和 [题目描述] 给定二叉搜索树的根结点 root,返回值位于范围 [low, high] 之间的所有结点的值的和. 示例1: 输入: ...

  8. 【python】Leetcode每日一题-二叉搜索树节点最小距离

    [python]Leetcode每日一题-二叉搜索树节点最小距离 [题目描述] 给你一个二叉搜索树的根节点 root ,返回 树中任意两不同节点值之间的最小差值 . 示例1: 输入:root = [4 ...

  9. Leetcode题目96.不同的二叉搜索树(动态规划-中等)

    题目描述: 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 示例: 输入: 3 输出: 5 解释: 给定 n = 3, 一共有 5 种不同结构的二叉搜索树: 1 3 3 2 ...

随机推荐

  1. 闭包和let块级作用域

    还是先从一个题目开始: 写一个隔1s输出数组的一项的函数. 如果可以用ES6语法,则可以这么写: function print (arr) { for (let i = 0; i < arr.l ...

  2. .Net core 使用Swagger

    接触到项目的时候,用了很久的Swagger,发现Swagger真的非常好用,不但方便了调试Web Api,还生成了Api 文档,真是非常的好用啊. 然后我想搞懂到底如何使用Swagger,所以自己建了 ...

  3. Linux Centos6.5 升级默认Python2.6.6到Python2.7.13

    以下例子基于python 2.7.9,其他版本同理.大致的命令都是差不多的,安装完成之后,输入Python --vertion ,看到系统默认的版本已经替换为2.7版本了 1.下载python wge ...

  4. Shell中的${}、##和%%使用范例

    假设定义了一个变量为,代码如下: file=/dir1/dir2/dir3/my.file.txt 可以用${ }分别替换得到不同的值: ${file#*/}: 删掉第一个 / 及其左边的字符串:di ...

  5. systemd的新特性及常见的systemd unit类型分析

    systemd概述 )systemd是一种新的linux系统服务管理器,用于替换init系统,能够管理系统启动过程和系统服务,一旦启动起来,就将监管整个系统.在centos7系统中,PID1被syst ...

  6. SQL Server 2012 - 开窗函数

    -- 开窗函数:在结果集的基础上进一步处理(聚合操作) -- Over函数,添加一个字段显示最大年龄 SELECT * , MAX(StuAge) OVER ( ) MaxStuAge FROM db ...

  7. PHP通过curl向其它服务器发请求并返回数据

    在很多时候,我们都需要请求第三方的服务器来获取一些数据,比如token,比如百度的主动推送,那么我们的php如何实现向第三方服务器发请求呢?我们可以通过curl来实现 首先定义请求的url,然后创建h ...

  8. day 25 模块与包

    一.模块   模块就是一个包含了python定义和申明的文件,文件名就是模块的名字加上.py的后缀/ 模块的分类:     1.使用python编写的py文件     2.已被编译位共享库或者DLL或 ...

  9. Python中的封装,继承和多态

    面向对象的三大特性:封装,继承和多态 封装:在类的内部定义属性和方法,通过对象或类名来访问属性和方法,隐藏功能的实现细节,也可以设置访问权限. 广义的封装:实例化一个对象,给对象空间封装一些属性:狭义 ...

  10. Docker开篇之HelloWorld

    按照程序世界的惯例,我们应该以HelloWorld的程序为起点开始介绍.那么接下来我们就看看Docker的HelloWorld是如何运行的. 安装 Docker CE 由于我的系统是OSX,个人推荐使 ...