每天一道LeetCode-----生成由[1 : n]這n個數組成的所有二叉搜尋樹
Unique Binary Search Trees
給定數值n,計算有多少種不同的二叉搜尋樹能夠儲存
二叉搜尋樹滿足的條件
- 當前根節點的值大於左子樹節點的值
- 當前根節點的值小於右子樹節點的值
- 左右子樹同樣是二叉搜尋樹
根據上述規則可以看出,根節點值不同,形成的二叉搜尋樹就不同,那麼
假設選取i作為根節點值,根據二叉搜尋樹的規則,
對於由
對於由
由於每個分解的範圍都是連續遞增的,所以無需考慮具體數值。另G(n)表示由連續的n個數形成的二叉搜尋樹的個數
那麼G(n)為所求解,假設以i作為分界點,那麼左子樹為G(i-1),右子樹為G(n-i)
因為i可以取從1到n的任意一個數,所以
需要對G(0)和G(1)特殊處理,令其為1,即
程式碼如下
class Solution {
public:
int numTrees(int n) {
vector<int> dp(n + 1, 0);
dp[0] = dp[1] = 1 ;
for(int i = 2; i <= n; ++i)
{
for(int j = 1; j <= i; ++j)
{
//G(i) += G(j - 1) * G(n - j)
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
};
Unique Binary Search Trees II
不再是計算有多少個不同的二叉搜尋樹,而是將所有不同的二叉搜尋樹構造出來:smile:
還是以上面的題為基礎,假設選擇i作為分界點,那麼左子樹由
通過
通過
那麼可知以i作為根節點的二叉搜尋樹共有
程式碼如下
/**
* 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:
vector<TreeNode*> generateTrees(int n) {
return generateTrees(1, n);
}
private:
//返回由[start : end]組成的所有樹
vector<TreeNode*> generateTrees(int start, int end)
{
vector<TreeNode*> trees;
//如果只有一個元素,直接構建返回
if(start == end)
{
trees.emplace_back(new TreeNode(start));
return trees;
}
//範圍內無元素,直接返回
if(start > end)
{
return trees;
}
for(int i = start; i <= end; ++i)
{
//以i作為分界點獲取左右兩部分的子樹集合
vector<TreeNode*> leftTrees = generateTrees(start, i - 1);
vector<TreeNode*> rightTrees = generateTrees(i + 1, end);
//如果是空,手動增加nullptr節點,否則for迴圈進不去!!!
if(leftTrees.empty()) leftTrees.emplace_back(nullptr);
if(rightTrees.empty()) rightTrees.emplace_back(nullptr);
//依次組合所有可能
for(auto leftTree : leftTrees)
{
for(auto rightTree : rightTrees)
{
//構建以i為值的根節點,新增左右子樹,新增到結果中
TreeNode *root = new TreeNode(i);
root->left = leftTree;
root->right = rightTree;
trees.emplace_back(root);
}
}
}
//繼續返回上一層
return trees;
}
};
這兩道題比較重要,真的很重要:cry:
對於如何構建二叉搜尋樹,只需要將其拆分成左右兩部分,再組合集合。計算所有BST的數量利用的是動態規劃,公式推導一遍應該可以理解(Letex公式真的好用:smile:)