您的位置:首页 > 编程语言 > C#

平衡二叉树--c#求解--英雄会在线编程题目

2014-01-15 11:26 381 查看
这几天写了写了几道题,觉得这道平衡二叉树的题有点意思,就把他的c#算法写出来,不足之处请大家指点。

先看题目:

平衡二叉树

难 度 等 级:










题目详情

平衡二叉树的定义是递归定义的:

(1) 单个节点是平衡二叉树

(2)平衡二叉树的左右子树分别都是平衡二叉树

(3)平衡二叉树的左右子树高度差不超过1。

求n个节点有m个叶子节点的平衡二叉树个数 (0<m <= n<=20)。

例如:

n = 1,m = 1,输出:1;

n = 2,m = 1,输出:2;

n = 2,m = 2,输出:0。

分析:

1、看完这题,从n=2,m=1,有两种结果,说明,这道题要考虑左右树交换位置,即假设找到一个满足条件的平衡二叉树,左右子树交换位置,也可能得到一个答案。

2、二叉树的一般原理可以得到,n=左右子树的节点和+1

3、同理可以得到:m=左右子树的叶子数和

4、每一个层级的最少节点数=左右子树最少节点数之和(n>1)

这一点什么意思呢?

举例来说吧,一个节点,层级是1,,也只能是1,。

对于2个层级的平衡树,如果要满足条件,最少需要2个节点,1个叶子,最多3个节点,2个叶子

对于3个层级的平衡树,如果要满足条件:

最少节点=2级的最少节点数+1级的最少节点数+1

最少叶子=2级的最少叶子数+1级的最少叶子数

最多节点=2级的最多节点数*2+1

最多叶子=2级的最多叶子数*2

有了这个推理过程,我们很容易得到x级的平衡树的最少节点数、叶子数,最多节点数、叶子数

为什么要得到这个推论和结果呢?因为给我们的是节点数和叶子数,所以我们要知道这样的条件能够生成多少级别的平衡二叉树

思路:

通过上面的分析,我们就可以将问题转换为,对于n,m可以在层级为x的平衡二叉树上有多少种方案,

当x>2时,可以将x降级为左右树的可能出现情况,这样就能得到结果=left*right

1、首先构造这个最大、最小节点叶子数的字典,当然,临时求出来也行,反正规律已经分析出来的:

static Dictionary<int, List<int>> dic;

dic = new Dictionary<int, List<int>>();

for (int i = 1; i <= 6; i++)

{

List<int> list = new List<int>();

if (i == 1)

{

list.Add(1);

list.Add(1);

list.Add(1);

list.Add(1);

}

if (i == 2)

{

list.Add(2);

list.Add(1);

list.Add(3);

list.Add(2);

}

if (i > 2)

{

list.Add(dic[i - 1][0] + dic[i - 2][0]+1);

list.Add(dic[i - 1][1] + dic[i - 2][1] );

list.Add(dic[i - 1][2]*2 +1);

list.Add(dic[i - 1][3] * 2 );

}

dic.Add(i, list);

}

这里自己定义list[0]表示最少节点数,依次向后表示最少叶子数,最大节点数,最大叶子数

2、构造了范围集字典,下一步创建结果集字典

因为3级的结果={左1级*右边2级+左边2级*右边1级+左边2级*右边2级)的结果和

所以,我们先将1级和2级的结果得到:

TreeResult.Add("1,1,1", 1);

TreeResult.Add("2,2,1", 2);

TreeResult.Add("2,3,2", 1);

我们还是自定义数据结构,key表示:层级,节点个数,叶子个数,value表示这样的平衡树有几种情况

因此我们可以这样构造一个递归函数:

public static int cal(int n,int m,int level)

{

int result = 0;

string key = "";

key = level.ToString() + "," + n.ToString() + "," + m.ToString();

string tmpkey="";

if (TreeResult.ContainsKey(key))

{

return TreeResult[key];

}

if (level < 3)

{

TreeResult.Add(key, 0);

return 0;

}

int left = 0;

int right = 0;

int rightnode = 0;

int rightleaf = 0;

int count =0;

if (m > dic[level][3] || m < dic[level][1])

{

TreeResult.Add(key, 0);

return 0;

}

for (int i = level - 2; i <= level - 1; i++)

{

for (int j = level - 2; j <= level - 1; j++)

{

if (i != level - 1 && j != level - 1)

{

continue;

}

for (int leftnode = dic[i][0]; leftnode <= dic[i][2]; leftnode++)

{

if (leftnode > n - 1)

{

break;

}

rightnode = n - 1 - leftnode;

for (int leftleaf = dic[i][1]; leftleaf <= dic[i][3]; leftleaf++)

{

if (leftleaf > m)

{

break;

}

rightleaf = m - leftleaf;

if (rightleaf <= 0)

{

break;

}

tmpkey=i.ToString() + "," + leftnode.ToString() + "," + leftleaf.ToString();

if (!TreeResult.ContainsKey(tmpkey))

{

left = cal(leftnode, leftleaf, i);

if (!TreeResult.ContainsKey(tmpkey))

{

TreeResult.Add(tmpkey, left);

}

}

else

{

left = TreeResult[tmpkey];

}

tmpkey = j.ToString() + "," + rightnode.ToString() + "," + rightleaf.ToString();

if (!TreeResult.ContainsKey(tmpkey))

{

right = cal(rightnode, rightleaf, j);

if (!TreeResult.ContainsKey(tmpkey))

{

TreeResult.Add(tmpkey, right);

}

}

else

{

right = TreeResult[tmpkey];

}

count += left * right;

}

}

}

}

if (!TreeResult.ContainsKey(key))

{

TreeResult.Add(key, count );

}

result = count;

return result;

}

表示对于n个节点,m个叶子,在level层级下有多少种符合条件的平衡二叉树

在level层级降级过程,还需要考虑n,m如何分配给左右子树各多少个,由于有了前面的范围集合字典,我们可以遍历范围内的节点和叶子个数,超出范围的表示不可能出现,直接返回0

ok,大功告成,当输入n,我们首先判断有n个节点的平衡二叉树可能出现在哪些层级范围内,然后调用cal函数就可以了,累加得到结果。

由于题目说了n<=20,所以在前面,我们的字典只构造了6级

提交代码,通过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: