Binary Search Tree二叉搜索树笔记⑧--构造篇
前言
在上一篇基操篇我们讲述了BST的判断合法性和增删改查,下面来学习BST的构造,读完本文你对下面的题目会有更深入的了解。
Leetcode
96.不同的二叉搜索树
95.不同的二叉搜索树 II
不同的二叉搜索树
这是一道穷举的题目,首先我们做个例子:比如输入n=3
,那么就有以下几个情况
这个是一个正宗的穷举问题,那么有什么方法可以正确的穷举BST的数量呢?
再看一个例子 比如给算法输入n=5
也就是要求他从1,2,3,4,5
里面找数字构成BST
显然会有五种情况,因为每个数字都可以作为根节点,那么我们固定3为根节点,看到底能构成多少个BST
因为BST左小右大的性质,很明显3为根节点的时候,左子树节点就是1,2
右子树节点就是4,5
那么左子树的组合数和右子树的组合数的乘积就是3作为根节点的时候的BST个数
在代码方面,其实我们只需要递归就可以了1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 计算闭区间[1,n]组成的BST数量
const numTree = n=>{
return count(1,n);
const count = (start,end)=>{
// base case
if(start>end)return 1;
let res = 0;
for(let i=start;i<=end;i++){
let left = count(start,i-1);
let right = count(i+1,end);
res += left*right;
}
return res;
}
}
但是这样做显然是不行的,因为会存在很多重叠子问题,我们可以利用一个memo备忘录来解决这个问题
1 | var numTrees = function(n) { |
不同的二叉搜索树II
题目类似,但是最后要返回全部组合的BST
我们不难想到还是要用memo去记录我们的子问题,并且这里还存在一个关键,就是我们可以用简单的memoKey来帮助我们记录1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35var generateTrees = function(n) {
if(n===0)return [];
const memo = new Map();
const count = (lo,hi)=>{
let res = [];
// base case
if(lo>hi){
res.push(null);
return res;
}
//定义memoKey
let memoKey = `${lo}&${hi}`;
//查找备忘录
if(memo.has(memoKey)){
return memo.get(memoKey);
}
// 穷举root节点的所有BST可能
for(let i=lo;i<=hi;i++){
// i作为根节点
let leftTree = count(lo,i-1);
let rightTree = count(i+1,hi);
// 穷举root的所有左右子树组合
for (const left of leftTree) {
for (const right of rightTree) {
res.push(new TreeNode(i,left,right))
}
}
}
//存放res
memo.set(memoKey,res);
return res;
}
return count(1,n);
}
总结
BST的构造核心还是BT的构造,但是不同的是,我们可以根据BST的root划分左右去穷举并构造。穷举的过程就是看左右子树有多少种可能的过程,最后可能性相乘就是组合。还学习到了memo的记录方式来排除重复子问题,以及用简单的memoKey。