待字闺中之LISS问题
来源:互联网 发布:淘宝店铺主营怎么修改 编辑:程序博客网 时间:2024/04/29 07:22
待字闺中是一个不错的面试题集。
Largest Independent Set
含义如下:给定一颗二叉树,找到满足如下条件的最大节点集合:集合中的任意两个结点之间,都没有边。如下图所示
10
/ \
20 30
/ \ \
40 50 60
/ \
70 80
LIS大小为5,集合为{10,40,60,70,80}
就是给你一颗二叉树,任意两个结点都没有相同边的集合。
通常来讲,树的问题一般都是可以通过递归来解决的。递归是自顶向下的分析问题分析
原问题是否能够分解为子问题。
我们先从LIS集合大小入手,设f(x)为以x为根的数的LIS的大小,根据题目的定义我们可以知道:
当x不在LIS中时,f(x)=sum(所有儿子节点的f(儿子))
当x在LIS中的时候,则x的儿子节点肯定不在LIS中,考虑孙子节点,
则f(x)=sum(所有孙子节点的f(孙子)) + 1,后面的1是x本身。
1) Optimal Substructure:
Let LISS(X) indicates size of largest independent set of a tree with root X.
LISS(X) = MAX { (1 + sum of LISS for all grandchildren of X),
(sum of LISS for all children of X) }
If a node is considered as part of LIS, then its children cannot be part of LIS,
but its grandchildren can be. Following is optimal substructure property.
这种二叉树的问题,都是用递归的方法来实现了。
LISS(X) = MAX { (1 + sum of LISS for all grandchildren of X),
(sum of LISS for all children of X) }
根据上面这条公式,我们可以使用递归的方法来实现。原理很简单,就是通过统计它的孩子节点和孙子节点的个数,然后得到其中的最大值返回,代码实例如下所示:
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int data): data(data), left(NULL), right(NULL)
{}
};
int LISS(TreeNode *root)
{
if(root == NULL)
{
return 0;
}
int childsize = LISS(root->left) + LISS(root->right);
int leftsize = 0;
int rightsize = 0;
if(root->left != NULL)
leftsize = LISS(root->left->left) + LISS(root->left->right);
if(root->right != NULL)
rightsize = LISS(root->right->left) + LISS(root->right->right);
return max(leftsize + rightsize + 1, childsize);
}
int main()
{
TreeNode *root = new TreeNode(20);
root->left = new TreeNode(8);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(12);
root->left->right->left = new TreeNode(10);
root->left->right->right = new TreeNode(14);
root->right = new TreeNode(22);
root->right->right = new TreeNode(25);
cout << LISS(root);
system("pause");
}
有没有更优的方法呢?
上面的递归过程中,子问题重复的比较多。最明显的就是,x的儿子节点x的父节点的孙子节点,几乎都要重复计算,所以改进空间很大。改进的方法,最直接的就是采用缓存将计算过的子问题,缓存起来,待后面直接使用,很简单,却又是非常实用的。
那么动态规划如何解呢?动态规划是自底向上解决问题,对于上面的递归过程,如何表示x是否在LIS中呢?
解法如下:
dp[0,1][x]表示以节点x为根的子树不取或取x的结果,第一维取0,表示x不在LIS中,第一维取1,表示x在LIS中;
dp[0][leaf]=0,dp[1][leaf]=value of the leaf
dp[0][x]=max of max dp[t=0,1][y is son of x], dp[1][x]=sum of dp[0][y is son of x] + value of x.
最后取max(dp[0][root],dp[1][root])
这里比较有意思的是第一维来表示第二维的节点,作为根节点,是否在LIS中。上面的过程在,前序或者后序的基础之上进行都可以,原则就是一点,有儿子的,就先计算完儿子,再计算父节点。
- 待字闺中之LISS问题
- 待字闺中之鸡蛋挺住体
- 待字闺中之数组统计分析
- 待字闺中之逆序分析
- 待字闺中之此起彼伏分析
- 待字闺中之最大乘积
- 【待字闺中】
- 待字闺中之Magic Index 分析
- 待字闺中之相伴一生分析
- 待字闺中之巧妙排序分析:
- 待字闺中之死亡小岛分析
- 待字闺中之interleave字符串分析
- 待字闺中之相差最大分析
- 待字闺中之兄弟数字分析
- 待字闺中之最长等差数列分析
- 待字闺中之删除字符分析
- 待字闺中之最大乘积分析
- 待字闺中之单链表和之恋
- zoj 3810 A Volcanic Island(构造)
- Mysql 中不支持中文的办法
- 关于fork()
- netstat -i 和ifconfig -s的输出解释
- java线程面试题
- 待字闺中之LISS问题
- PostgreSQL常用数据类型
- 小菜学编程之感悟
- struts2总结(一)
- 不错的一些大数据分析tips
- poj1631基于lower_bound的实现
- 关于眼镜保护的几点做法
- 数据结构——RMQ(范围最小值查询)
- MySQL中截取时间范围