题目 不同的二叉搜索树 II
给定一个整数 n,生成所有由 1 … n 为节点所组成的 二叉搜索树 。
示例:
输入:3
输出:
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
解释:
以上的输出对应以下 5 种不同结构的二叉搜索树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
提示:
0 <= n <= 8
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii
思路
这个题目是真的有点让人摸不着头脑。因为搜索树的形状不仅和插入数字的顺序有关,而且上面例子中,以2作为开头插入的数字,此后无论先插入1还是先插入3,得到的答案都是相同的。而以1或3开头的时候,顺序不同就是完全不同的二叉搜索树。
按惯例没思路做不出就去看看题解。一个明确给出的解题思路是,枚举从左到右的所有数字作为根节点,然后用该数字将数组分为左右两个部分。和之前的戳气球相当类似,我们将数组设置为[left, ……, root, ……, right]的话,那么root就是将数组分为[left, root - 1] 和[root + 1, right],然后继续递归,把[left, root - 1]作为新的数组,再次划分。就在这划分和递归的过程中得到某一划分的全部左子树或右子树,将左右子树排列组合后得到完整的树,然后递归得到最终答案。
代码实现
这是递归的思路,按照这个思路呢,可以得到如下的代码:
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
vector<TreeNode*> answer;
int left = 1, right = n;
if (left > right) {
return answer;
}
if (left == right) {
TreeNode* root = new TreeNode(1);
answer.push_back(root);
return answer;
}
answer = generate(left, right);
return answer;
}
vector<TreeNode*> generate(int left, int right) {
if (left >= right) {
vector<TreeNode*> answer;
if (left > right) {
answer.push_back(NULL);
}
else {
answer.push_back(new TreeNode(left));
}
return answer;
}
vector<TreeNode*> answer;
for (int i = left; i <= right; i++) {
vector<TreeNode*> leftanswer = generate(left, i - 1);
vector<TreeNode*> rightanswer = generate(i + 1, right);
for (int j = 0; j < leftanswer.size(); j++) {
for (int k = 0; k < rightanswer.size(); k++) {
TreeNode* root = new TreeNode(i);
root->left = leftanswer[j];
root->right = rightanswer[k];
answer.push_back(root);
}
}
}
return answer;
}
};
运行结果双90+,意外地还挺不错的。