直觉背后使用笛卡尔积来寻找独特的BST数量

时间:2017-08-30 17:38:40

标签: c++ algorithm binary-search-tree

我正在解决一个LeetCode问题。问题是:

  

给定n,可以生成多少结构上唯一的BST,用于存储1...n的值?例如,对于n=3,可以生成总共5个唯一BST,如下所示:

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

最大的upvoted解决方案使用DP和以下递归公式:

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

其中G(n)表示可以为n生成的唯一BST的数量。代码如下:

class Solution {
public:
    int numTrees(int n) {
        vector<int> G(n+1);
        G[0]=G[1]=1;

        for(int i=2; i<=n; i++)
            for(int j=1; j<=i; j++)
                G[i]+=G[j-1]*G[i-j];

        return G[n];
    }
};

虽然我或多或少了解发生了什么,但我并不理解为什么我们采用笛卡尔产品(而不是简单的添加,这更直观)。根据我的理解:

G[i] += G[j-1] * G[i-j];

应改为:

G[i] += G[j-1] + G[i-j];  //replaced '*' with a '+'

这是因为,我认为i作为当前根的唯一BST的数量应该是其左右BST数量的总和(?)子树。我确实尝试了一些例子,但不知何故,数字在原始解决方案中神奇地成倍增加(*),最终答案出现在G[n]中。

有人可以提供使用笛卡尔积而不是求和的直观解释吗?

注意:原始问题为here,解决方案为here。此外,原始代码是Java,而我发布了上面写的C ++变体。

1 个答案:

答案 0 :(得分:1)

您可以通过数学归纳法,然后将其应用于子问题以获得结果。或者只是检查小值,然后选择更高的值。

例如: -

No of nodes      BST representation

1   -->    [1]

2   -->  [2]  [1]
         /     \
        [1]    [2]

3   -->  [1]
           \
           [2]
             \
             [3]

         [2]
         / \
        [1] [3]

          [3]
          /
       [2]
       /
      [1]
4  --> 
        [1]
      /     \
     NUM{}  NUM of keys with 3 val NUM{2,3,4}

      [2]
      /  \
    NUM{1} NUM{3,4}

      [3]
      /  \
    NUM{1,2} NUM{4}

          [4]
         /     \
    NUM{1,2,3}  NUM{}

从第4个案例中,您可以清楚地了解到,我们必须简单地将每个树中的左右子树分组的可能方式的数量相乘。对于给定数量的值,我们必须添加它们。这就是使用笛卡儿产品的原因。

该产品基本上为我们提供了所有可能的订单。 例如:

  

G[i] += G[j-1] * G[i-j];这里j-1个节点在左边(我们可以假设   不失一般性)和i-j个节点到右子树。和   现在你可以用G[j-1]方式安排左子树了   以G[i-j]方式使用右子树。现在想想你可以安排多少种方式   有这个左边的原始树和rigth子树?它会   乘。因为左右子树的每个组合都会给出   崛起为一种独特的树形象。

这也解释了为什么我们定义G[0]=1,因为它符合我们在这里做事的方式。而且没有价值的安排的数量也是一种安排。所以它被认为是1.