LeetCode 95.不同的二叉搜索树 II
题目描述
给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树 。
解题
对一个二叉搜索树的中序遍历结果就是得到一个有序的序列
{
1
,
2
,
3...
n
}
\{1, 2, 3...n\}
{1,2,3...n},本题的目的是要求所有能得到这个有序序列的二叉搜索树。观察这个有序序列,每一个数字都可以作为根节点,它将整个序列一分为二,左边一部分,右边一部分,左边的数字在二叉树上对应其左子树部分,右边的数字对应其右子树部分,这样根节点、左右子树大致划分完成。同样地,对左右子树也可以有类似的划分,即左边的每一个数字都可以作为左子树的根节点,同样能将左子树划分为左右两部分,这样把整个复杂的问题分解成具有相似处理方式的子问题,就可以借助循环或迭代完成了。这里可以想到,应该是先解决子树的问题,然后回到父节点,再解决更高一层的树的问题,因此使用递归更合适。
整个问题是将序列
{
1
,
2
,
3...
n
}
\{1, 2, 3...n\}
{1,2,3...n}转化为二叉搜索树,子问题是将某一段子序列转化为二叉搜索树的子树,因此应当设计这样一个递归函数,它接收两个参数,指定数字范围,即子序列,返回这个子序列能够组成的所有二叉搜索(子)树,返回结果可以以数组的形式,在当前迭代过程中,如果参数表示的数字范围是有效的,当前数字范围的每一个数字
m
m
m的左右部分
[
1
,
m
−
1
]
[1,m-1]
[1,m−1]和[m+1,n]调用迭代函数的返回结果表示所有的左右子树,以此建立所有子树的集合并返回这个集合。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
vector<TreeNode *> generateTrees(int l, int r){
if (l > r) return {NULL};
vector<TreeNode *> cur_nodes;
for (int n=l; n <= r; ++n){
vector<TreeNode *> left_nodes(std::move(generateTrees(l, n-1))); //所有左子树集合
vector<TreeNode *> right_nodes(std::move(generateTrees(n+1, r))); //所有右子树集合
TreeNode *cur_node;
//建立所有当前子树的集合
for (int i=0; i<left_nodes.size(); ++i){
for (int j=0; j<right_nodes.size(); ++j){
cur_node = new TreeNode(n);
cur_node->left = left_nodes[i];
cur_node->right = right_nodes[j];
cur_nodes.emplace_back(cur_node);
}
}
}
return cur_nodes;
}
public:
vector<TreeNode*> generateTrees(int n) {
if (n==0) return vector<TreeNode*>();
vector<TreeNode *>out(std::move(generateTrees(1, n)));
return out;
}
};
上面方法实现过程中有一个小小的缺陷,那就是同样一个子序列可能会计算多次,因此可以借助记忆化的方式,把子序列的结果保存,当需要时直接返回保存的结果,不需要再计算一次,这里实际上就是保存所有子序列所能转化的子树。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
vector<vector<vector<TreeNode*>>> nodes;
vector<TreeNode*>generateTrees(int l, int r){
if (l > r) return vector<TreeNode*>{NULL};
if (!nodes[l][r].empty()) return nodes[l][r];
vector<TreeNode *> cur_node_vect;
for (int n=l; n<=r; ++n){
vector<TreeNode*> l_nodes = generateTrees(l, n-1);
vector<TreeNode*> r_nodes = generateTrees(n+1, r);
for (auto i : l_nodes){
for (auto j:r_nodes){
TreeNode *cur_node = new TreeNode(n);
cur_node->left = i;
cur_node->right = j;
cur_node_vect.emplace_back(cur_node);
}
}
}
return cur_node_vect;
}
public:
vector<TreeNode*> generateTrees(int n) {
if (n==0) return vector<TreeNode *>();
nodes.resize(n+1, vector<vector<TreeNode*>>(n+1));
return generateTrees(1, n);
}
};