LeetCode之Unique Binry Search Trees
4月份很快就过半了,最近都在看WPF,有点落伍了...本来想写一点读书笔记的,还没想好要怎么写。所以为了能够达到每月一篇博客的目标,今天先说一个LeetCode上的面试题:Unique Binary Search Trees。
题目简单翻译过来就是说:
给定n个不同节点,问:可以构造出多少种异构的二叉搜索树。比方说n=3时有5种:
3 3 3 2 1
\ / / / \ \
2 2 1 1 3 2
/ / \ \
1 1 2 3
一般来说,遇到这种问题多半是找规律,总结出数学公式然后解决之。找规律前,首先要看我们有哪些可以利用的条件。
这里可用的条件很有限但也很明确:二叉搜索树。也就是其任意一部分二叉树都满足左子树节点都小于(或者大于)根节点;右子树节点都大于(或者小于)根节点。
我们已经有了n=3的结果,那么来看看n=4时的情况。我们知道,任何一个节点都可以成为一个根节点,那么:
- 如果以1为树根,那么剩下的三个节点都分布在该树的右子树上;
- 如果以2为树根,那么节点1必然是其左子树上的唯一节点,而3、4只可能在其优节点上;
- 如果以3为树根,那么节点2、3在其左子树上,而节点4是其右子树上的唯一节点;
- 如果以4为树根,那么甚于节点都在其左子树上;
这个简单的分析过程很快就将规律呈现了出来!!
对于n=4的情况,其异构结果就是各种独立情况下,左子树和右子树异构方式的排列数之和。用公式表示就是:f(4) = f(0) * f(3) + f(1) * f(2) + f(2) * f(1) + f(3) * f(0)。整一个典型的递归实现。唯一需要考虑的点就是你需要缓存一下中间数据,因为f(2)和f(3)分别被调用了2次。
1 class Solution { 2 public: 3 int numTrees(int n) { 4 static vector<int> cached(1, 1); 5 if (n > cached.size()) 6 { 7 cached.resize(n, 0); 8 } 9 10 if (0 == n) 11 { 12 return 1; 13 } 14 15 if (cached[n - 1] != 0) 16 { 17 return cached[n - 1]; 18 } 19 else 20 { 21 for (int i = 0; i < n; ++i) 22 { 23 cached[n - 1] += numTrees(i) * numTrees(n - i - 1); 24 } 25 26 return cached[n - 1]; 27 } 28 } 29 };
顺带因为打算以后要有Python,所以附带上Python的代码。刚开始学着写Python,写着有点难过...(有没有更好的写法?)
1 class Solution: 2 # @return an integer 3 def numTrees(self, n): 4 if 0 == n: 5 return 1 6 7 cached = [1] 8 if n > len(cached): 9 result = 0; 10 for i in range(n): 11 index = n - i - 1 12 13 left_part_result = self.numTrees(i) 14 right_part_result = self.numTrees(index) 15 16 result += left_part_result * right_part_result 17 18 if index == len(cached): 19 cached[len(cached):] = [right_part_result] 20 21 cached[len(cached):] = [result] 22 23 return result 24 else: 25 return cached[n - 1];
这题目的背景是一个称之为Catalan Number的数。也可以参看百度百科。通过了解Catalan Number,我们会发现他的诸多应用。比方说凸多边形的最优三角划分就是这个问题的拓展。
posted on 2014-04-18 01:04 wpcockroach 阅读(510) 评论(0) 编辑 收藏 举报