2022-09-24 17:41阅读: 27评论: 0推荐: 0

力扣-96-不同的二叉搜索树

小米2020的秋招笔试卷遇到了

n个节点可以构成多少不同的二叉搜索树?

  • f(1) = 1
  • f(2) = f(1) + f(1)
  • f(3) = f(2) + f(1)*f(1) + f(2)
  • … …
    由此,我们可以得到递推式:
    f(n) = f(n-1) + f(n-2)\*f(1) + … + f(1)\*f(n-2) + f(n-1)
    打表是这样的:

    case 1: return 1;
    case 2: return 2;
    case 3: return 5;
    case 4: return 14;
    case 5: return 42;
    case 6: return 132;
    case 7: return 429;
    case 8: return 1430;
    case 9: return 4862;
    case 10: return 16796;
    case 11: return 58786;

它的推导过程是怎么推导的呢?
两个函数:

  • G(n):表示n个不同节点组成的不同的二叉搜索树数量
  • F(i,n):表示以i为根节点,n个节点组成的二叉搜索树的数量

对于序列{1~n},从中依次选择i作为根节点构造不同的二叉搜索树,因为根节点不同,所以一定是不同的二叉搜索树
而对于其左右子树,递归上述过程
那么G(n)=F(1,n)+…+F(n,n)
又对于F(i,n)而言,左子树不同的二叉搜索树数量为:G(i-1)=F(1,i-1)+…+F(i-1,i-1),右子树G(n-i)

G(n)=G(0)*G(n)+……+G(n)*G(0)=G(i-1)*G(n-i)

一个看起来那么复杂的题做出来却是这么简单的代码

class Solution {
public:
int numTrees(int n) {
vector<int> dp(n+1);
dp[0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
dp[i] += dp[j - 1] * dp[i - j];
return dp[n];
}
};

它恰好就是力扣-96题

直达链接

二叉搜索树

复习一下二叉搜索树

  • 左子树节点小于根节点
  • 右子树节点大于根节点
    我记起来的就是二叉搜索树的中序遍历结果是一个升序数组,那么对二叉搜索树进行中序遍历,在这个过程中判断新加入的值是否比上一个值大

非常要注意的是节点值相同不满足二叉搜索树定义

class Solution {
public:
bool res = true;// 因为递归方法不能有返回值,所以定义全局的变量记录结果
long preNum = (long)INT_MIN-1;
void inorderTraversal(TreeNode* root) {
if (!root) return;
inorderTraversal(root->left);
if (root->val <= preNum) {
res = false;
return;
}
else preNum = root->val;
inorderTraversal(root->right);
}
bool isValidBST(TreeNode* root) {
inorderTraversal(root);
return res;
}
};

这里if判断中的return能够结束整个递归过程吗?其实是不行的,他只能结束自己向下的分支,就像第一句return也不会结束掉整个递归过程一样,所以说是有效率损失的,多余的遍历检查

本文作者:YaosGHC

本文链接:https://www.cnblogs.com/yaocy/p/16720002.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(27)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起