95. 不同的二叉搜索树 II
题目描述
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
解题思路
二叉搜索树:根节点的值大于左子树所有节点的值,小于右子树所有节点的值,且左子树和右子树也同样为二叉搜索树。
思路一: 递归
假设当前序列长度为 n,如果我们枚举根节点的值为 i,那么根据二叉搜索树的性质我们可以知道左子树的节点值的集合为 [1…i−1],右子树的节点值的集合为 [i+1…n]。而左子树和右子树的生成相较于原问题是一个序列长度缩小的子问题,因此我们可以想到用回溯的方法来解决这道题目
- 定义函数generate(start, end),函数表示当前值的集合为 [start, end],返回序列 [start, end] 生成的所有可行的二叉搜索树
- generate(start, i - 1) 和 generate(i + 1, end),获得所有可行的左子树和可行的右子树
- 从可行左子树集合中选一棵,再从可行右子树集合中选一棵拼接到根节点上,并将生成的二叉搜索树放入结果数组即可
- 当 start > end 的时候,当前二叉搜索树为空,返回空节点即可
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number} n
* @return {TreeNode[]}
*/
var generateTrees = function(n) {
const generate = function (start, end) {
let allTrees = [];
if (start > end) {
return [null];
}
// 枚举可行根节点
for (let i = start; i <= end; i++) {
// 获得所有可行的左子树集合
let leftTrees = generate(start, i - 1);
// 获得所有可行的右子树集合
let rightTrees = generate(i + 1, end);
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (let ln of leftTrees) {
for (let rn of rightTrees) {
let currTree = new TreeNode(i);
currTree.left = ln;
currTree.right = rn;
allTrees.push(currTree);
}
}
}
return allTrees;
}
return generate(1, n);
};
优化版
利用JSON.stringify([start, end])
作为key, 缓存结果
优化版代码如下:
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number} n
* @return {TreeNode[]}
*/
var generateTrees = function(n) {
const memo = new Map();
const generate = function (start, end) {
let allTrees = [];
if (start > end) {
return [null];
}
const key = JSON.stringify([start, end]);
const memoVal = memo.get(key);
// 如果缓存当中有就直接拿
if (memo.has(key) && memoVal) return memoVal;
// 枚举可行根节点
for (let i = start; i <= end; i++) {
// 获得所有可行的左子树集合
let leftTrees = generate(start, i - 1);
// 获得所有可行的右子树集合
let rightTrees = generate(i + 1, end);
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (let ln of leftTrees) {
for (let rn of rightTrees) {
let currTree = new TreeNode(i);
currTree.left = ln;
currTree.right = rn;
allTrees.push(currTree)
}
}
}
// 将结果集放入到缓存中
memo.set(key, allTrees);
return allTrees;
}
return generate(1, n);
};
参考资料
https://leetcode.cn/problems/unique-binary-search-trees-ii/solution/by-masx200-p4x4/