平衡二叉樹--c#求解--英雄會在線編程題目

      這幾天寫了寫了幾道題,覺得這道平衡二叉樹的題有點意思,就把他的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級

 

提交代碼,通過。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章