题目
给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
示例 1:
输入:n = 3
输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]
示例 2:
输入:n = 1
输出:[[1]]
/**
* 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 {
public:
vector<TreeNode*> generateTrees(int n) {
if( n<1 ) return generate(1, 0);
return generate(1,n);
}
vector<TreeNode*> generate(int start, int end){
vector<TreeNode*> subTree;//储存所有的根节点
if(start > end){//递归退出条件起始数字大于终止数字
subTree.push_back(NULL);//不能直接返回
//如果左子树为空,右子树不为空,在后续的for循环中根本无法组装成新的二叉搜索树,所以至少要有一个空节点
return subTree;
}
//查找以k为根节点的二叉搜索树
for(int k=start; k<=end; k++){
vector<TreeNode*> left = generate(start,k-1);//储存所有左子树的根节点
vector<TreeNode*> right = generate(k+1, end);//储存所有右子树的根节点
//将左子树和右子树组装起来,将根节点储存在向量中
for(int i=0; i<left.size(); i++){
for(int j=0; j<right.size(); j++){
TreeNode *root = new TreeNode(k);
root->left = left[i];
root->right = right[j];
subTree.push_back(root);
}
}
}
return subTree;
}
};
-
时间复杂度O(nGn),Gn为第n个卡特兰数,即n个点的二叉搜索树的数量
-
空间复杂度O(nGn)
-
思路
- 递归函数传入的参数为起始数字与终止数字
- 递归的终止条件为起始数字大于终止数字,此时返回一个只有一个空指针的向量
- for循环中计算从start到end,以每一个数字为根节点时的二叉搜索树。传入start到k-1,递归调用得到左子树的所有可能结果。传入k+1到end, 递归调用得到右子树的所有可能结果。用双重for循环将每一种左子树、右子树与根节点组装起来,返回组装后的根节点向量。
-
优化:备忘录法
- 用空间换时间,避免重复计算
- 开一个二维数组,存储每次计算的根节点,在1的基础上加四行代码
/**
* 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 {
public:
vector<TreeNode*> generateTrees(int n) {
memo.resize(n+1, vector<vector<TreeNode*>>(n+1));//2、设置数组大小
return generate(1,n);
}
private:
vector<vector<vector<TreeNode*>>> memo;//1、记忆化数组
vector<TreeNode*> generate(int start, int end){
vector<TreeNode*> subTree;
if(start>end){
subTree.push_back(nullptr);
return subTree;
}
if(memo[start][end].empty()==false) return memo[start][end];//记忆化判断,是否已经搜索过这种情况了
for(int k=start ; k<=end; ++k){
vector<TreeNode*> leftSubs=generate(start, k-1);
vector<TreeNode*> rightSubs=generate(k+1, end);
for(auto i: leftSubs){
for(auto j : rightSubs){
TreeNode *root=new TreeNode(k);
root->left = i;
root->right =j;
subTree.push_back(root);
}
}
}
return memo[start][end]=subTree;//记录这次搜索的结果
}
};