n個結點,不同形態的二叉樹(數目+生成)

題目鏈接:

  不同的二叉查找樹:http://www.lintcode.com/zh-cn/problem/unique-binary-search-trees/

  不同的二叉查找樹 II:http://www.lintcode.com/zh-cn/problem/unique-binary-search-trees-ii/

不同形態二叉樹的數目:

樣例

  給出n = 3,有5種不同形態的二叉查找樹:

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

分析

  ?可以分析,當n=1時,只有1個根節點,則只能組成1種形態的二叉樹,令n個節點可組成的二叉樹數量表示為h(n),則h(1)=1; h(0)=0;

?????? 當n=2時,1個根節點固定,還有2-1個節點。這一個節點可以分成(1,0),(0,1)兩組。即左邊放1個,右邊放0個;或者左邊放0個,右邊放1個。即:h(2)=h(0)*h(1)+h(1)*h(0)=2,則能組成2種形態的二叉樹。

????? 當n=3時,1個根節點固定,還有2個節點。這2個節點可以分成(2,0),(1,1),(0,2)3組。即h(3)=h(0)*h(2)+h(1)*h(1)+h(2)*h(0)=5,則能組成5種形態的二叉樹。

以此類推,當n>=2時,可組成的二叉樹數量為h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0)種,即符合Catalan數的定義,可直接利用通項公式得出結果。

令h(1)=1,h(0)=1,catalan數(卡特蘭數)滿足遞歸式:?

  h(n)= h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (其中n>=2)

  另類遞歸式:

h(n)=((4*n-2)/(n+1))*h(n-1);

  該遞推關系的解為:

  h(n)=C(2n,n)/(n+1) (n=1,2,3,...)

  由此想到了上次說的"N個數依次入棧,出棧順序有多少種?", ?同樣用的也是卡特蘭數。

  ?http://www.cnblogs.com/hujunzheng/p/4845354.html

代碼

class Solution {
public:/*** @paramn n: An integer* @return: An integer*/long long C(int n, int m){n = n-m+1;long long ans = 1;for(int i=1; i<=m; ++i){ans *= n++;ans /= i;}return ans;}int numTrees(int n) {// write your code herereturn C(2*n, n)/(n+1);}
};

?

構建不同形態二叉樹:

樣例

  給出n = 3,生成所有5種不同形態的二叉查找樹:

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

  其實通過樣例,我們可以發現n個結點構造不同形態二叉樹的過程,1,2,3.....n個結點,枚舉每一個結點為根結點(假設為root, 1<=root<=n), 那么(1,2..root-1)和(root+1, root+2...n)分別是root的左右子樹。每一步不斷地重復上述過程,最終會得到所有形態的二叉樹。

算法實現

  先弱弱的說一下自己錯誤的實現,因為遞歸實現的時候會得到不同的二叉樹,那么如何判斷n個結點正好生成了二叉樹呢?于是用了一個變量useNode(=0),表示當前已經用了多少個結點建樹。當useNode等于n的時候說明產生了一棵符合要求的樹,接著拷貝一下剛才生成的樹,然后放入vector中,繼續建造下一棵符合條件的二叉樹。

錯誤代碼:

/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/
class Solution {
public:/*** @paramn n: An integer* @return: A list of root*/vector<TreeNode *> ans;int cntNode=0;//節點的總數TreeNode *curRoot = NULL;void copyT(TreeNode * &tmp, TreeNode *T){if(T){tmp = new TreeNode(T->val);copyT(tmp->left, T->left);copyT(tmp->right, T->right);}}void buildT(TreeNode * &T, int ld, int rd, int useNode){if(ld > rd) return;for(int root=ld; root<=rd; ++root){T = new TreeNode(root);if(ld==1 && rd==cntNode)curRoot = T;if(useNode+1==cntNode){//這個樹已經建立完畢,拷貝一下吧TreeNode *tmp = NULL;copyT(tmp, curRoot);ans.push_back(tmp);}buildT(T->left, ld, root-1, useNode+1);buildT(T->right, root+1, rd, useNode+root-ld+1);}}vector<TreeNode *> generateTrees(int n) {// write your code herecntNode = n;TreeNode *T = NULL;buildT(T, 1, n, 0);if(n == 0) ans.push_back(T);return ans;}
};

  后來運行之后,看到錯誤的答案與正確答案的對比,如下:

  當n=4的時候

  輸出

[{1,#,2,#,3,#,4},{1,#,2,#,4,3},{1,#,3,2,4},{1,#,4,2,#,#,3},{1,#,4,3,#,2},{2,1,3,#,#,#,4},{2,1,4,#,#,3},{3,2,4,1},{4,1,#,#,2,#,3},{4,1,#,#,3,2},{4,2,#,1,3},{4,3,#,1,#,#,2},{4,3,#,2,#,1}]

  期望答案

[{1,#,2,#,3,#,4},{1,#,2,#,4,3},{1,#,3,2,4},{1,#,4,2,#,#,3},{1,#,4,3,#,2},{2,1,3,#,#,#,4},{2,1,4,#,#,3},{3,1,4,#,2},{3,2,4,1},{4,1,#,#,2,#,3},{4,1,#,#,3,2},{4,2,#,1,3},{4,3,#,1,#,#,2},{4,3,#,2,#,1}]

  也就是少了{3,1,4,#,2},以3為根結點的二叉樹為什么會少了呢?仔細想想,3結點的左孩子可以是1,也可以是2,那么左孩子為1的情況就被忽略了,此時useNode并不等于n,然后就換成左孩子為2結點的情況了。

正確代碼:

/*** Definition of TreeNode:* class TreeNode {* public:*     int val;*     TreeNode *left, *right;*     TreeNode(int val) {*         this->val = val;*         this->left = this->right = NULL;*     }* }*/
class Solution {
public:/*** @paramn n: An integer* @return: A list of root*/vector<TreeNode *> buildT(int ld, int rd){vector<TreeNode *> ans;if(ld == rd) {TreeNode *T = new TreeNode(ld);ans.push_back(T);return ans;}if(ld > rd){ans.push_back(NULL);return ans;}for(int i=ld; i<=rd; ++i){vector<TreeNode *> ansLeft = buildT(ld, i-1);vector<TreeNode *> ansRight = buildT(i+1, rd);for(auto lx : ansLeft)for(auto rx : ansRight){TreeNode *T = new TreeNode(i);T->left = lx;T->right = rx;ans.push_back(T);}}return ans;}vector<TreeNode *> generateTrees(int n) {// write your code herevector<TreeNode *> ans = buildT(1, n);return ans;}
};

  分析:在確定當前結點X后,那么X的左孩子結點(或右孩子結點)可能會有多個,那么就把這些可能的結點都存到vector中,然后從左孩子集合中任選出lx結點,以及從右孩子集合中選出rx結點,那么lx和rx就確定了一種形態的二叉樹。

轉載于:https://www.cnblogs.com/hujunzheng/p/5040334.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/531372.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/531372.shtml
英文地址,請注明出處:http://en.pswp.cn/news/531372.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c++ stringstream(老好用了)

前言&#xff1a; 以前沒有接觸過stringstream這個類的時候&#xff0c;常用的字符串和數字轉換函數就是sscanf和sprintf函數。開始的時候就覺得這兩個函數應經很叼了&#xff0c;但是畢竟是屬于c的。c中引入了流的概念&#xff0c;通過流來實現字符串和數字的轉換方便多了。在…

mount --bind的用處

&#xff08;一&#xff09;mount --bind介紹 mount --bind的作用是將兩個目錄連接起來&#xff0c;例如&#xff1a;mount ---bind /dir1 /dir2 是將dir1目錄掛載到dir2目錄上&#xff0c;下面來實際演示一下&#xff1a; 上面的操作中首先創建了dir1 dir2兩個目錄&#xf…

gcc -strip編譯選項的作用

從字面上來看strip的意思是脫衣服、拆卸&#xff0c;那么gcc --strip的作用大概能猜錯來了。 沒錯就是有選擇地除去行號信息、重定位信息、調試段、typchk 段、注釋段、文件頭以及所有或部分符號表。 一旦使用該命令&#xff0c;則很難調試文件的符號&#xff0c;因此&#x…

lintcode 落單的數(位操作)

題目1 落單的數 給出2*n 1 個的數字&#xff0c;除其中一個數字之外其他每個數字均出現兩次&#xff0c;找到這個數字。 鏈接&#xff1a;http://www.lintcode.com/zh-cn/problem/single-number/ 樣例 給出 [1,2,2,1,3,4,3]&#xff0c;返回 4 挑戰 一次遍歷&#xff0c;常數級…

旋轉圖像

旋轉圖像 給定一個NN的二維矩陣表示圖像&#xff0c;90度順時針旋轉圖像。 看個例子 算法1&#xff1a; 如上圖所示&#xff0c;設一個N階二維矩陣&#xff0c;則將矩陣從外向里可以分成N/2個圈&#xff0c;例如&#xff08;1 2 3 4 8 12 16 15 14 13 9 5&#xff09;這是最外邊…

嵌入式開發板模擬器:QEMU

前兩天看微信公眾號時發現了一個嵌入式模擬器&#xff0c;感覺很不錯&#xff0c;自己動手安裝了一個&#xff0c;折騰了幾天&#xff0c;下載一直是個問題&#xff0c;特此記錄如下 模擬器大家應該都聽說過&#xff0c;有的小伙伴打游戲也會安裝模擬器&#xff0c;今天我們介紹…

gcc: weak_alias如何使用

本文主要說明weak和alias是什么和如何使用它 __attribute__是用來說明函數的屬性&#xff0c;weak和alias分別是兩個屬性。 &#xff08;一&#xff09;強符號和弱符號&#xff1a; 強符號&#xff1a;已經初始化的全局變量和未被weak修飾的函數弱符號&#xff1a;未初始化的全…

靜態Include和動態Include測試并總結

主要代碼 hjzgg.css .center-div{width:auto;margin-left: 40%;margin-right: 40%;display: block;position: absolute;top:0px;left:0px; }.text-div{margin-top: 80px; }.hjzgg-div{color:transparent;font-size:20px;font-weight: bold;letter-spacing:2px;-webkit-animatio…

linux終端常用快捷鍵

CTRLALTT 打開終端 CTRLD 關閉終端 CTRL SHIFT "" 放大終端字體 CTRL “-” 縮小終端字體 CTRL r 查找歷史命令 CTRLu 刪除光標前面所有內容 CTRLw 刪除光標左邊的單詞 CTRL k 刪除光標后面的所有內容 CTRLL 清除當前屏幕內容 CTRLa 光標移到開始位置 CTRLe 光標移到…

ueditor的配置和使用

ueditor下載好之后直接復制到項目的WebContent目錄下&#xff0c;并將ueditor\jsp\lib下的jar包復制或者剪切到項目的lib目錄下。先看一下效果&#xff0c;如下&#xff1a; 1.文件的上傳 首先在ueditor/jsp目錄下找到config.json文件&#xff0c;就拿Image上傳來說吧。 "…

windows上搭建NFS服務器

在進行嵌入式開發的時候&#xff0c;我們常用的做法是搭建NFS服務器&#xff0c;然后使把文件系統、調試程序放在NFS服務器上&#xff0c;這樣可以方便調試&#xff0c;以前都是在linux里面開啟NFS服務器&#xff0c;今天來說下window里的nfs服務器–haneWin 一、軟件安裝和使…

計算機是如何啟動的?從未上電到操作系統啟動

計算機是如何啟動的&#xff0c;網絡上很多博文1都從 BIOS 程序的加載開始說起&#xff0c;有的也跳到 BIOS 程序加載 Bootloader 階段。個人認為把這個過程稱為操作系統是如何被加載并啟動應該更加貼切一點。同時&#xff0c;也有計算機硬件大神的文章[1][5]詳細分析計算機加電…

Hibernate注解

前言&#xff1a; 最近正在學習Hibernate通過注解&#xff08;annotation&#xff09;來管理映射關系&#xff0c;以前都是通過XML映射文件。下面拿個小例子說一下。 數據庫物理模型&#xff1a; 數據庫的描述&#xff1a; 一篇博客隨筆可以分到不同的類中&#xff0c;一個類中…

js表單動態添加數據并提交

情景1&#xff1a;已經存在form對象了&#xff0c;動態為form增加對象并提交 function formAppendSubmit(){var myform$(#newArticleForm); //得到form對象var tmpInput$("<input typetext nameblogArticleForm.articleContent/>");tmpInput.attr("value&…

*++p和*p++的區別

首先你應該明白* 和 的優先級是相同的&#xff0c;而且他們的結合性是從又往左的 #include <stdio.h>int main(int argc ,char * argv[]) {int str[]{1,2,3,4,5,6,7,8,9,10};int *p str;int a *p;//a*p ,pp1即a1&#xff0c;p&str[1]int b *p;//pp1,b*p即p&s…

zyUpload+struct2完成文件上傳

前言&#xff1a; 最近在寫自己的博客網站&#xff0c;算是強化一下自己對s2sh框架的理解。期間遇到了很多問題&#xff0c;這些問題在寫之前都考慮過&#xff0c;感覺也就是那樣吧。但正真遇到了&#xff0c;也挺讓人難受的。就利用zyUpload這個js插件實現文件的上傳&#xff…

gbd的簡單使用(一)

這篇文章將gdb的簡單使用&#xff0c;通過此篇文章你能學習到使用gdb進行調試程序 在Linux中編寫程序時&#xff0c;如何進行程序的debug工作呢&#xff1f;今天來介紹下gdb這個工具&#xff0c;可以在Linux下直接man gdb查看幫助信息 &#xff08;一&#xff09;gdb命令介紹 …

java發送內嵌圖片郵件

前言&#xff1a; 博客系統中需要郵件服務的功能&#xff0c;以前寫過類似的功能&#xff0c;不過功能太簡單了&#xff0c;僅僅是發送文本內容&#xff0c;現在嘗試一下發送內嵌圖片郵件&#xff01; 準備工作&#xff1a; 請參考&#xff1a;http://www.cnblogs.com/hujunzhe…

調試跟蹤利器---strace

通過這篇文章你會學習到strace的用法&#xff0c;strace可以幫助你高效地定位進程中的一些錯誤&#xff0c;關于strace的用處有很多&#xff0c;可以自行發掘 前面我們講解了gdb調試程序,這篇文章介紹另一個調試跟蹤工具strace&#xff0c;同樣你可以在linux下執行man strace查…

MBR、DBR、FAT32基礎小知識

MBR-------主引導記錄 1.創建時間&#xff1a;由分區軟件&#xff08;Fdisk/PartitionMagic/Windows 2000/Windows XP安裝 工具等&#xff09;給 硬盤分區時建立的。 2.功能 &#xff1a;存放硬盤分區信息和引導系統時檢查分區。 3.作用范圍&#xff1a;MBR和虛擬MBR控制著整個…