题目
给定一个整数 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii
分治+memo
虽然有了前面这道题打基础,但是还是看答案理解了好久。
我想到了要从1到n,选取不同的数字做根。然后左边的数字做左子树,右边的数字可以做右子树。但是没想到用vector来得到各种可能的左子树的集合。再得到右子树的集合。然后合并成新的树。
我觉得我这里的memo用的挺巧妙的,将int,int的组合转为string来做key。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
using MapType = unordered_map<string, vector<TreeNode*>> ;
vector<TreeNode*> generateTrees(int n) {
// 这道题利用分治的思路我认为应该是这样想的。
// left, root, right这样的思想
if(!n)
return {};
MapType memo;
return generateTrees(1, n+1, memo);
}
string getKey(int start, int end)
{
return to_string(start) + "_" + to_string(end);
}
vector<TreeNode*> generateTrees(int start, int end, MapType &memo)
{
if(!memo.count(getKey(start, end)))
{
vector<TreeNode*> result;
if(start >= end){
result.push_back(nullptr);
}
for(int i = start; i < end; i++){
// 所有左子树的可能
auto leftTrees = generateTrees(start, i, memo);
auto rightTrees = generateTrees(i+1, end, memo);
for(auto leftNode : leftTrees)
{
for(auto rightNode : rightTrees)
{
auto currNode = new TreeNode(i);
currNode->left = leftNode;
currNode->right = rightNode;
result.push_back(currNode);
}
}
}
memo[getKey(start, end)] = result;
}
return memo[getKey(start, end)];
}
};