力扣-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也不会结束掉整个递归过程一样,所以说是有效率损失的,多余的遍历检查

posted @ 2022-09-24 17:41  YaosGHC  阅读(37)  评论(0)    收藏  举报