刷题---树篇---96. 不同的二叉搜索树

30 篇文章 1 订阅
10 篇文章 0 订阅

96. 不同的二叉搜索树

难度:中等

给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种?

示例:

输入: 3
输出: 5
解释:
给定 n = 3, 一共有 5 种不同结构的二叉搜索树:

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

————————————————————————————————————————————————————————

类似题:

刷题---树篇---95. 不同的二叉搜索树Ⅱ

(假设已经完全理解了bst的基础知识)

本题例子给了n=3的情况,可以先从n=1开始思考。

很明显,n=1时只有一个节点,那么输出结果必是1.

n=2时,有两个节点,一个为根,一个必为子节点(可能为左也可能为右)。根据bst的特性,左子树一定小于根节点,右子树一定大于根节点。那么就有两种情况:

   1                                            2

       \                                    /

           2                            1

(额外问题:如果只是一棵普通的二叉树会有多少种情况?)

那么对于n=3时,根据bst的特性以及对n=2的分析可知,我们需要先确定根节点,再进行排列生成bst。

若根节点为1时,其余的节点都比1要大,所以都在右边,那么对于这颗右子树,又可以选择2或者3作为根节点,而选择2或3本质和n=2的情况又是一样的(有序的n个节点生成bst),这样一来,当根节点为1时,就有两种bst的生成方法。

分别是:

    1                                                                                  1                                           

         \                                                                                      \  

            2                                                                                          3

               \                                                                                 /

                   3                                                                      2

再选择2做为根节点,此时再根据bst的特性可以知道,剩下的1,3分别作为左右子树,所以只有一种情况。

                2

           /            \

     1                      3

最后再选择3作为根节点,与选择1作为根节点的情况类似,只不过现在是需要在右子树这边进行分析,同理可得:

             3                                                                                  3                                         

         /                                                                                  /

       2                                                                                1                 

    /                                                                                      \     

1                                                                                           2

这样,我们就把n=3的所有情况都找出来了。

通过上面分析我们得到两个关键点:

1.必须先选出根节点,再通过bst的特性对左右进行分开讨论;

2.需要用到前n-1次的结果。

第一点有点类似分治的思路,第二点可以dp(动态规划)来满足。

go实现:

func numTrees(n int) int {
    if n == 1 {
        return 1
    }

    dp := make([]int,n+1)

    dp[0] = 1
    dp[1] = 1
    dp[2] = 2


    for i:=3;i<=n;i++ {
        for j:=1;j<i;j++ {
            //以j为根
            dp[i] += dp[j]*dp[i-j-1]
        }
        dp[i] += dp[i-1]
    }

    return dp[n]
}

代码不复杂,前面分析清楚理解之后还是比较好实现的。

 for i:=3;i<=n;i++ {
        for j:=1;j<i;j++ {
            //以j为根
            dp[i] += dp[j]*dp[i-j-1]
        }
        dp[i] += dp[i-1]
    }

通过这段代码,我们选择i作为根节点,1...i-1作为右子树的节点,i+1....n作为左子树的节点。

而这些有序的节点,是严格按照bst的特性进行选择的,所以本质上我们只用关注每个子树上节点的个数,对应到dp[i]表示节点个数为i,生成的bst的个数。

第一个for循环,遍历从i=3到i=n的情况,第二个for循环,计算每个i的生成不同bst的个数。

dp[j]表示左边(或者右边)子树中节点的个数,dp[i-j-1]则表示另外一边子树节点的个数。

另外,因为在计算上可以直接把握本质,找子节点个数即可,但是实际上每个节点的数值不同,所以j<i而不是j<=i/2.

dp[i] += dp[i-1]

当i作为根节点时,右子树上节点个数必为i-1个,且摆放方式唯一。

最后即可得想要的结果。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值