不同的二叉搜索树

力扣题目链接(opens new window)

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

示例:

思路

题意分析

先找一下关系

当n = 1时,如果元素就是1,以1为头节点

1

当n = 2时,分别以1和2为头节点

  1     2
/ \
2 1

然后当n = 3时的情况就是示例中给的那几种

找找有什么规律

当n = 3且使用1为头节点时,其子树的布局和n = 2时的布局是一样的(注意看1-2、2-1和3-2、2-3的方向,是不是一样的,数值不同没有影响)

当n = 3且使用2为头节点时,其左右子树布局和n = 1时的布局是一样的(n = 1是左右子树为空,也算1种情况)

当n = 3且使用3为头节点时,其子树的布局和n = 2时的布局是一样的

某种程度上,n = 3的二叉搜索树种类情况可以由n = 2以及n = 1推导出来

因此,n = 3时,二叉搜索树种类 = 头节点为1时的情况+头节点为2时的情况+头节点为3时的情况,来组成

即,头1+头2+头3

公式描述

接下来分析不同头节点时的情况

从图中可以看出,头节点为1时有:

 1       1
\ \
3 2
/ \
2 3

头节点为1时有多少种二叉搜索树可以用以下公式描述:

头1 = 左子树有0个节点时有几种二叉搜索树 * 右子树有2个节点时有几种二叉搜索树;(2种)

如何理解?

头节点为1来构建二叉搜索树的话,如果左子树只给0个节点,那么左子树的类型就只有1种(也就是空);然后给右子树2个节点的话,那么右子树就可以有3-2和2-3两种情况。

左右子树的情况组合在一起就得到以下结论:

​ 当n = 3时,使用1作为头节点可以构建2种(1*2)不同的二叉搜索树

还不理解再举个例子:

       10
/ \
5个节点 10个节点

上述以10(数值无所谓)为头节点的二叉树,其左右子节点的情况如上

那么,可以构成的二叉树的种类一共是:5*10种

同理可以得到头2、头3的公式描述:

头2 = 左子树有1个节点时有几种二叉搜索树 * 右子树有1个节点时有几种二叉搜索树;(1种)

头3 = 左子树有2个节点时有几种二叉搜索树 * 右子树有0个节点时有几种二叉搜索树;(2种)

与示例对照的话发现是可以对上的

还是先来五部曲吧

五步走

1、确定dp数组的含义

根据题目所求可以得到

dp[i]:输入为i时有dp[i]种不同的二叉搜索树

2、确定递推公式

由前面的分析可以知道,当输入n为3时,可以组成的二叉搜索树种类(也就是dp[3])是有分别使用1、2、3作为头节点时产生的种类相加得到的。

即,

dp[3] = 头1+头2+头3
dp[3] = dp[0]dp[2] + dp[1]dp[1] + dp[2]dp[0];

明确了上述问题后可以开始讨论dp[i]

dp[i]可以从哪里求出来?

那肯定是由以1、2、3...i为头节点的所有情况相加得出,于是我们需要枚举所有头节点情况

j 来代表头节点数,那么该二叉搜索树的左子树有多少个节点?答案是 j-1

(举个例子来理解:示例中以3为头节点时,其左子树是不是有两个节点)

那么该二叉搜索树的右子树有多少个节点?答案是 i-j

因为我们这里是二叉搜索树,现在以i为头节点了,右子树的节点值一定都比 i 大,总节点数是 i ,那么留给右子树的节点数就是i-j了

套用dp数组的定义:

输入为 j-1 时有 dp[j-1] 种不同的二叉搜索树;

输入为 i-j 时有 dp[i-j] 种不同的二叉搜索树;

那么dp[i]怎么求?

根据 公式描述 中的讨论可得:dp[i] = dp[j-1] * dp[i-j];(只是当前j下的dp[i])

因为 j 是代表遍历所有头节点的情况,所以要把头节点为1~i的情况都相加才能得出最后的dp[i]

即递推公式应该是:dp[i] += dp[j-1] * dp[i-j];(i个节点有多少种不同的二叉搜索树)

怎么理解?

拿前面的例子dp[3]来说

dp[3] = dp[0]dp[2] + dp[1]dp[1] + dp[2]dp[0];

此处j的遍历范围是1~i,可以写成以下形式

dp[3] = dp[1-1]dp[3-1] + dp[2-1]dp[3-2] + dp[3-1]dp[3-3];

3、确定初始化方式

前面的讨论也说了dp[0]、dp[1] (即,n=0、n=1)可以用于推出后续情况

那么就要对这两者进行初始化吗?其实只需要初始化dp[0]就行了,dp[1]也可以通过dp[0]推出

dp[0]的含义是什么?输入的i是0,0个节点有多少种不同的二叉搜索树呢?答案是1个,因为空二叉树也是一种二叉搜索树

所以dp[0] = 1;

并且这也符合递推公式的要求,因为如果有空节点,其种类如果是0,那么不论后面的其他子树有几种情况,结果都是0,就没有意义了,因此空节点的种类应该是1(如果左右子树都空的话,也就是1*1=1,递推还能继续进行下去)

4、确定遍历顺序

还是从dp[3]来看

dp[3] = dp[0]dp[2] + dp[1]dp[1] + dp[2]dp[0];

dp[3]都是由小于3的状态累加推导来的,所以就要从小到大遍历,才可以利用之前遍历的状态

for(int i = 1; i <= n; ++i){
for(int j = 1; j <= i; ++j){
dp[i] += dp[j-1] * dp[i-j];
}
}

代码

class Solution {
public:
int numTrees(int n) {
//定义dp数组
vector<int> dp(n + 1);
//初始化dp数组
dp[0] = 1;
//dp[1] = 1;//不用初始化dp[1],否则按理来说dp[1]应该是1,手动初始化会使其变为2
//遍历
for(int i = 1; i <= n; ++i){//此处i确实要取3,所以有等于号
for(int j = 1; j <= i; ++j){
dp[i] += dp[j - 1] * dp[i - j];
}
}
// cout << dp[1]<< endl;//打印dp数组debug
return dp[n];//确实要返回n的dp而不是n-1
}
};

ps:真难啊动态规划

【LeetCode动态规划#04】不同的二叉搜索树(找规律,有点像智力题)的更多相关文章

  1. C# leetcode 之 096 不同的二叉搜索树

    C# leetcode 之 096 不同的二叉搜索树 题目描述 给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种? 二叉搜索树定义 左子树上所有节点的值小于根节点, 右子树上左右 ...

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

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

  3. LeetCode 95 | 构造出所有二叉搜索树

    今天是LeetCode专题第61篇文章,我们一起来看的是LeetCode95题,Unique Binary Search Trees II(不同的二叉搜索树II). 这道题的官方难度是Medium,点 ...

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

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

  5. [LeetCode] Serialize and Deserialize BST 二叉搜索树的序列化和去序列化

    Serialization is the process of converting a data structure or object into a sequence of bits so tha ...

  6. [LeetCode] Binary Search Tree Iterator 二叉搜索树迭代器

    Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the ro ...

  7. LeetCode 109——有序链表转化二叉搜索树

    1. 题目 2. 解答 2.1. 方法一 在 LeetCode 108--将有序数组转化为二叉搜索树 中,我们已经实现了将有序数组转化为二叉搜索树.因此,这里,我们可以先遍历一遍链表,将节点的数据存入 ...

  8. [LeetCode] 109. 有序链表转换二叉搜索树

    题目链接 : https://leetcode-cn.com/problems/convert-sorted-list-to-binary-search-tree/ 题目描述: 给定一个单链表,其中的 ...

  9. LeetCode 中级 - 有序链表转换二叉搜索树(109)

    给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定的有序链表: [-10 ...

  10. LeetCode 109. 有序链表转换二叉搜索树(Convert Sorted List to Binary Search Tree)

    题目描述 给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定的有序链表: ...

随机推荐

  1. 常用的DOS指令及部分快捷键

    常用的DOS指令及部分快捷键 1.dos打开方式 ​ win + R打开运行,输入cmd,打开dos 2.常用的Dos指令 a.切换盘号 方法 ​ 直接输入对应盘加" :" D: ...

  2. java mybatisplus+springboot服务器跨域问题

    项目本地增删改测试正常,上传到  阿里服  页面出现了 跨域报错问题! 解决方案:添加一个过滤器 package com.rl;import org.springframework.stereotyp ...

  3. 打包python文件为exe程序 vscode

    一.项目下虚拟环境下载pyinstaller.exe 打包 1.检查是否下载  pyinstaller: 如果没有在vscode终端输入:pip3 install pyinstaller 安装成功后下 ...

  4. phpmyadmin scripts/setup.php 反序列化漏洞(WooYun-2016-199433)(Kali)

    ​ phpmyadmin 2.x版本中存在一处反序列化漏洞,通过该漏洞,攻击者可以读取任意文件或执行任意代码. 通过vulhub靶场进行复现操作 1.首先搭建靶场环境(采用Kali) cd vulhu ...

  5. c++学习9 结构体

    一 结构体赋值 结构体赋值的方法有三种,逐个成员赋值,整体赋值和拷贝赋值. 设一个结构体有struck student{ int age;char ch[32]; }: 逐个成员赋值:student ...

  6. nvm在windows下安装与使用

    1.卸载本地已经安装的所有node 2.nvm下载 下载地址https://github.com/coreybutler/nvm-windows ,选择nvm-noinstall.zip 放在本地盘, ...

  7. #科技 #资讯 #生活 RTX 4080显卡在欧跌破建议零售价, 小鹏回应自研电池, Meta因泄漏超5亿用户资料被罚款 ,黑猫投诉开启2022“你我同心 反诈同行”系列活动,这就是今天的其它大新闻

    今天是2022年11月29日 十一月初六 现在是下午15:29 下面是今天的其他大新闻 #NEWS 1 #RTX 4080在欧跌破建议零售价 ( IT 之家 )据 PCGamesHardware 报道 ...

  8. 方法(Java)

    什么是方法? 基本介绍 在其他语言中也叫函数 System.out.println();类名.对象.方法: Java方法是语句的集合,它们在一起执行一个功能 方法是解决一类问题的步骤的有序集合 方法包 ...

  9. 如何卸载cdr x8?怎么把cdr x8彻底卸载删除干净重新安装的方法【转载】

    标题:如何卸载cdr x8?怎么把cdr x8彻底卸载删除干净重新安装的方法.cdr x8显示已安装或者报错出现提示安装未完成某些产品无法安装的问题,怎么完全彻底删除清理干净cdr x8各种残留注册表 ...

  10. dockerflie

    FROM newbe36524/aspnet:5.0-buster-slim AS base ENV TZ=Asia/Shanghai WORKDIR /app EXPOSE 3400 3400 RU ...