leecode 解题总结:96. Unique Binary Search Trees

#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
/*
问题:
Given n, how many structurally unique BST's (binary search trees) that store values 1...n?

For example,
Given n = 3, there are a total of 5 unique BST's.

   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3

分析:这个和之前的不同,之前是找出所有不同的二叉查找树并打印。而这道题目只需要
计算不同二叉查找树的数目。
因此,应该可以用递归或dp来做。
找规律:距离,以1作为根节点,那么:后续左右孩子结点{2,3}
{1,2,3}可以认为是选中{1}后,构建{2,3}的二叉查找树,但是似乎不能拆分来看。
因为根节点会决定左右孩子的走向。
设dp[i][j]表示从数字i都数字j的二叉查找树的个数
那么dp[1][n]= dp[1][i-1] * dp[i+1][n] 的累加求和, i从1到n
其中dp[i][i] = 1, dp[i][j] = 1 , 当i > j时
也就是把之前的那道题目拆分

输入:
1
3
输出:
1
5

关键:
1 选定某个根节点为i,然后计算结点i的左子树[1...i-1]的个数,计算结点i的右子树[i+1...n]的个数
则以i为根节点的总的二叉查找树个数=左子树个数 * 右子树个数
对i从1到n遍历,然后累加每个根节点的二叉查找树的个数即可。

2但是超时了,需要记忆化搜索,但是需要注意下标不能溢出
		//不断从start到end中选取根节点
		int totalResult = 0;
		for(int i = start ; i <= end ; i++)
		{
			leftNum = dfs(start , i-1 , dp );//计算得到左子树的个数
			rightNum = dfs(i+1 , end, dp);//计算得到右子树的个数
			result = leftNum * rightNum;//以结点i为根节点总的二叉查找树个数=左子树个数*右子树个数
			if(i-1 >= 0)
			{
				dp.at(start).at(i-1) = leftNum;//这边可能溢出
			}
			if(i+1 <= end)
			{
				dp.at(i+1).at(end) = rightNum;
			}
			totalResult += result;
		}
*/

class Solution {
public:
	int dfs(int start , int end , vector< vector<int> >& dp )
	{
		int result = 0;
		//插入一个空结点,某个结点的左孩子或者右孩子为空
		if(start > end)
		{
			result++;
			//dp.at(start).at(end) = result;
			return result;
		}
		//当前结点作为单独的结点。某个结点的左孩子或者右孩子不为空,值为start
		if(start == end)
		{
			result++;
			//dp.at(start).at(end) = result;
			return result;
		}
		//记忆化搜索,
		if(dp.at(start).at(end) != 0)
		{
			return dp.at(start).at(end);
		}
		int leftNum;
		int rightNum;
		//不断从start到end中选取根节点
		int totalResult = 0;
		for(int i = start ; i <= end ; i++)
		{
			leftNum = dfs(start , i-1 , dp );//计算得到左子树的个数
			rightNum = dfs(i+1 , end, dp);//计算得到右子树的个数
			result = leftNum * rightNum;//以结点i为根节点总的二叉查找树个数=左子树个数*右子树个数
			if(i-1 >= 0)
			{
				dp.at(start).at(i-1) = leftNum;//这边可能溢出
			}
			if(i+1 <= end)
			{
				dp.at(i+1).at(end) = rightNum;
			}
			totalResult += result;
		}
		return totalResult;
	}

    int numTrees(int n) {
		vector< vector<int> > dp(n+1 , vector<int>(n+1 , 0));
        int result = dfs(1 , n , dp);
		return result;
    }
};

void process()
{
	 int num;
	 Solution solution;
	 int result;
	 while(cin >> num )
	 {
		 result = solution.numTrees(num);
		 cout << result << endl;
	 }
}

int main(int argc , char* argv[])
{
	process();
	getchar();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值