劍指offer上關(guān)于樹的題目匯總

樹的題目通常可以用遞歸解決,遞歸過程的本質(zhì)是棧,因而理論上遞歸也可以用循環(huán)加堆棧(或者隊列)解決

關(guān)于遞歸

遞歸非常容易讓人思路混亂盟榴,看到網(wǎng)上有一種思路覺得很有用,就是假設(shè)子問題已經(jīng)完美處理婴噩,你只需思考最終問題的處理思路擎场,子問題的處理思路和最終問題的處理思路一樣,這樣思路就會清晰很多几莽。
以下代碼示例均為python版本

題目一:從上往下打印二叉樹
題目描述:

從上往下打印出二叉樹的每個節(jié)點迅办,同層節(jié)點從左至右打印。

算法思路:

很明顯用層次遍歷就可以解決章蚣,即廣度遍歷站欺,從上往下打印,即每一層打印完之后需要按照父節(jié)點們的順序繼續(xù)打印子節(jié)點纤垂,
符合隊列先進先出的特點矾策,因而需要借助隊列+循環(huán)判斷就可以解決。
即借助隊列峭沦,將根結(jié)點加入隊列贾虽,每遍歷到一個結(jié)點,將該結(jié)點移除出隊列并將該結(jié)點的左右節(jié)點加入隊列吼鱼,重復(fù)這個過程蓬豁,直至隊列為空绰咽。


來源:劍指offer
關(guān)鍵字:隊列 循環(huán)

代碼如下

# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    # 返回從上到下每個節(jié)點值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        if root is None:
            return []
        tempnode = []
        tempnode.append(root)
        valres = []
        while (len(tempnode) > 0):
            node = tempnode.pop(0)
            valres.append(node.val)
            if node.left is not None:
                tempnode.append(node.left)
            if node.right is not None:
                tempnode.append(node.right)
        return valres

題目二:二叉樹的鏡像
題目描述:

操作給定的二叉樹地粪,將其變換為源二叉樹的鏡像取募。
如下圖:


來源:劍指offer
算法思路:

從題目可以知道二叉樹的鏡像其實可以看成是左右子結(jié)點交換的過程,如下圖:


來源:劍指offer

因而我們在前序遍歷(順序為根子樹->左子樹->右子樹)的基礎(chǔ)上驶忌,交換當前結(jié)點的左右子結(jié)點矛辕,就可以完成二叉樹的鏡像。
代碼如下

# -*- coding:utf-8 -*-
'''
    樹的鏡像
    思路:遞歸交換左右結(jié)點
'''
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution:
    # 返回鏡像樹的根節(jié)點
    def Mirror(self, root):
        # write code here
        if root is None:
            return root
        if root.left is None and root.right is None:
            return root
        tempNode = root.left
        root.left = root.right
        root.right = tempNode
        self.Mirror(root.left)
        self.Mirror(root.right)

關(guān)鍵字:遞歸 前序遍歷
題目三:二叉搜索樹的后序遍歷序列
題目描述:

輸入一個整數(shù)數(shù)組付魔,判斷該數(shù)組是不是某二叉搜索樹的后序遍歷的結(jié)果聊品。如果是則返回True,否則返回False几苍。假設(shè)輸入的數(shù)組的任意兩個數(shù)字都互不相同翻屈。

算法思路:

二叉搜索樹:

是指一棵空樹或者具有下列性質(zhì)的二叉樹:

若任意節(jié)點的左子樹不空,則左子樹上所有節(jié)點的值均小于它的根節(jié)點的值妻坝;
若任意節(jié)點的右子樹不空伸眶,則右子樹上所有節(jié)點的值均大于它的根節(jié)點的值;
任意節(jié)點的左刽宪、右子樹也分別為二叉查找樹厘贼;
沒有鍵值相等的結(jié)點。


來源:劍指offer

后序遍歷順序:左子樹->右子樹->根結(jié)點

1)遞歸方法
由后序遍歷順序可知圣拄,序列的最后一個元素為根結(jié)點嘴秸,根據(jù)二叉搜索樹的特點可知,左子樹的每個非空結(jié)點都不大于根結(jié)點庇谆,右子樹的每個非空結(jié)點都不小于根結(jié)點岳掐,題目中規(guī)定序列中各個結(jié)點都不重復(fù),因此可以確定題目中給的測試用例中饭耳,左子樹的每個結(jié)點勢必都小于根結(jié)點串述,右子樹的每個結(jié)點勢必都大于根結(jié)點。
因此從左往右查找寞肖,找到第1個大于根結(jié)點的值則說明這個元素往左邊的元素是左子樹纲酗,該元素及往右邊的元素到最后一個結(jié)點前為右子樹。
如果左子樹有任一元素大于根結(jié)點新蟆,或者右子樹有任一元素小于根結(jié)點耕姊,說明該序列不為二叉搜索樹遍歷序列。
以此方法進行遞歸判斷栅葡。

圖片

圖中最后一個元素8為根結(jié)點,元素9為從左往右序列中第一個大于根結(jié)點的值尤泽,以9往左為左子樹欣簇,9和9往右到最后一個元素8前為右子樹规脸。
觀察可知 如果符合二叉搜索樹,則右子樹序列元素都比根結(jié)點大
左右子序列以此方法遞歸可判斷熊咽。
代碼如下

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        if sequence is None or len(sequence) == 0:
            return False
        return self.VerifyBST(sequence)

    def VerifyBST(self,verifys):
        if len(verifys) <= 1:  # 只剩根結(jié)點
            return True
        root = verifys[-1]
        temps = verifys[:-1]
        lefts = []
        rights = []
        for i in range(len(temps)):
            if temps[i] > root:
                lefts = temps[0:i]
                if i <= len(temps) - 1:
                    rights = temps[i:-1]
                break
        else:
            lefts = temps
        for v in rights:
            if v < root:
                return False
        return self.VerifyBST(lefts) and self.VerifyBST(rights)

2)非遞歸方法(拍迹客網(wǎng)上看到的)
大致思路是根據(jù)后序遍歷,將當前結(jié)點A作為根結(jié)點横殴,遍歷結(jié)點A前面序列的值被因,如果當前序列元素值小于結(jié)點A的值,并且前一序列元素值也大于結(jié)點A的值 說明不是二叉搜索樹衫仑。

參考鏈接 爬嬗耄客網(wǎng)

截圖(侵刪):

圖片侵刪

關(guān)鍵字:遞歸 二叉搜索樹特點
題目四:二叉樹中和為某一值的路徑
題目描述:

輸入一顆二叉樹的根節(jié)點和一個整數(shù),打印出二叉樹中結(jié)點值的和為輸入整數(shù)的所有路徑文狱。路徑定義為從樹的根結(jié)點開始往下一直到葉結(jié)點所經(jīng)過的結(jié)點形成一條路徑粥鞋。

算法思路:

路徑指的是樹的根結(jié)點到葉結(jié)點所經(jīng)過的結(jié)點,因此題目其實是求從根結(jié)點到某一葉結(jié)點的路徑上所有結(jié)點的和是否為題目中要求的值瞄崇。
因為計算是從根結(jié)點開始呻粹,所以其實可以看成是樹的前序遍歷的基礎(chǔ)上計算路徑和,由于題目要求打印出路徑苏研,因而每次遍歷結(jié)點需要記錄下當前結(jié)點等浊,到達葉結(jié)點時需要判斷該路徑是否符合條件,當遞歸回退到上一個結(jié)點時需要從路徑中移除當前結(jié)點即路徑的最后一個結(jié)點摹蘑,記錄路徑可以用堆棧筹燕。
示例:


來源:劍指offer

根結(jié)點到葉結(jié)點加入堆棧 ,堆棧中加入序列為 10纹蝴,5庄萎, 4;
10+5+4不等于22塘安,不記錄路徑糠涛;
彈出4,回到父結(jié)點5兼犯,堆棧序列 10,5忍捡;
右葉結(jié)點7 進棧 ,堆棧序列 10,5,7,等于22 切黔,記錄路徑砸脊;
彈出7,回到5纬霞;
彈出5凌埂,回到10;
葉結(jié)點12進棧诗芜,堆棧序列 10,12 等于 22 瞳抓,記錄路徑埃疫;
所以符合條件的路徑為[10,5,7]和[10,12]。

# -*- coding:utf-8 -*-
"""
二叉樹中和為某一值的路徑
"""
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    # 返回二維列表孩哑,內(nèi)部每個列表表示找到的路徑
    def FindPath(self, root, expectNumber):
        return self.RealFindPath(root, 0, expectNumber, [], [])

    def RealFindPath(self, root, sum, expectNumber, path, allpath):
        if root is None:
            return allpath
        sum += root.val
        path.append(root.val)
        if root.left is None and root.right is None:
            if sum == expectNumber:
                allpath.append(path[:])
        if root.left:
            self.RealFindPath(root.left, sum, expectNumber, path, allpath)
        if root.right:
            self.RealFindPath(root.right, sum, expectNumber, path, allpath)
        # 回退到上個結(jié)點前彈出當前元素
        if len(path) > 0:
            num = path.pop()  # 彈出末尾元素
            sum = sum - num
        return allpath
關(guān)鍵字:遞歸 堆棧
題目五:對稱的二叉樹
題目描述:

請實現(xiàn)一個函數(shù)栓霜,用來判斷一顆二叉樹是不是對稱的。注意横蜒,如果一個二叉樹同此二叉樹的鏡像是同樣的胳蛮,定義其為對稱的。

算法思路:

遞歸方法:
如下圖丛晌,由對稱的二叉樹觀察得知仅炊,同一父節(jié)點的左子結(jié)點(6)的左結(jié)點(矩形1)和右子結(jié)點(6)的右結(jié)點(矩形1)如果不相等(一個為空另一個不為空也是不相等),或者同一父節(jié)點的左子結(jié)點(6)的右結(jié)點(圓形3)和右子結(jié)點(6)的左結(jié)點(圓形3)如果不相等(一個為空另一個不為空也是不相等)茵乱,則說明該二叉樹不為對稱二叉樹茂洒。


示例
# -*- coding:utf-8 -*-
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
    
class Solution:
    def isSymmetrical(self, pRoot):
        if pRoot is None:
            return True
        return self.IsRealSymmetrical(pRoot.left, pRoot.right)

    def IsRealSymmetrical(self, Lroot, Rroot):
        if (Lroot and Rroot is None) or (Rroot and Lroot is None):
            return False
        if Lroot is None and Rroot is None:
            return True
        if Lroot.val != Rroot.val:
            return False
        return self.IsRealSymmetrical(Lroot.left, Rroot.right) and self.IsRealSymmetrical(Lroot.right, Rroot.left)

關(guān)鍵字:遞歸 非遞歸
題目六:重建二叉樹
題目描述:

輸入某二叉樹的前序遍歷和中序遍歷的結(jié)果,請重建出該二叉樹瓶竭。假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復(fù)的數(shù)字督勺。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹并返回斤贰。

算法思路:

由前序序列和中序序列可得二叉樹智哀。由前序遍歷的遍歷過程可以知道,前序序列的第1個元素為根結(jié)點荧恍,在中序序列中找到根結(jié)點瓷叫,序列中根結(jié)點往左為左子樹,根結(jié)點往右為右子樹送巡。根據(jù)此方法遞歸可重建二叉樹摹菠,遞歸的本質(zhì)是棧(先進后出),因而最后遞歸返回的結(jié)點即為根結(jié)點骗爆。


來源:劍指offfer
關(guān)鍵字:遞歸

==============================
發(fā)現(xiàn)一個好玩的項目 ~
https://github.com/Wscats/piano

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末次氨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子摘投,更是在濱河造成了極大的恐慌煮寡,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件犀呼,死亡現(xiàn)場離奇詭異幸撕,居然都是意外死亡,警方通過查閱死者的電腦和手機外臂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門坐儿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事挑童±矍Γ” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵站叼,是天一觀的道長。 經(jīng)常有香客問我菇民,道長尽楔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任第练,我火速辦了婚禮阔馋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娇掏。我一直安慰自己呕寝,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布婴梧。 她就那樣靜靜地躺著下梢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪塞蹭。 梳的紋絲不亂的頭發(fā)上孽江,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音晌纫,去河邊找鬼焰扳。 笑死母剥,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的这刷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼娩井,長吁一口氣:“原來是場噩夢啊……” “哼暇屋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起撞牢,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤率碾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后屋彪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體所宰,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年畜挥,在試婚紗的時候發(fā)現(xiàn)自己被綠了仔粥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖躯泰,靈堂內(nèi)的尸體忽然破棺而出谭羔,到底是詐尸還是另有隱情,我是刑警寧澤麦向,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布瘟裸,位于F島的核電站,受9級特大地震影響诵竭,放射性物質(zhì)發(fā)生泄漏话告。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一卵慰、第九天 我趴在偏房一處隱蔽的房頂上張望沙郭。 院中可真熱鬧,春花似錦裳朋、人聲如沸病线。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽送挑。三九已至,卻和暖如春泛范,著一層夾襖步出監(jiān)牢的瞬間让虐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工罢荡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留赡突,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓区赵,卻偏偏與公主長得像惭缰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笼才,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 樹 記錄《劍指offer》中所有關(guān)于樹的題目漱受,以及LeetCode中的相似題目。 相關(guān)題目列表 題目 樹是一種最常...
    wenmingxing閱讀 1,407評論 2 13
  • 目錄 1骡送、什么是樹 2昂羡、相關(guān)術(shù)語 3、二叉樹 3.1摔踱、二叉樹的類型 3.2虐先、二叉樹的性質(zhì) 3.3、二叉樹的結(jié)構(gòu) 3...
    我哈啊哈啊哈閱讀 2,536評論 0 10
  • 數(shù)據(jù)結(jié)構(gòu)和算法--二叉樹的實現(xiàn) 幾種二叉樹 1派敷、二叉樹 和普通的樹相比蛹批,二叉樹有如下特點: 每個結(jié)點最多只有兩棵子...
    sunhaiyu閱讀 6,426評論 0 14
  • 一些概念 數(shù)據(jù)結(jié)構(gòu)就是研究數(shù)據(jù)的邏輯結(jié)構(gòu)和物理結(jié)構(gòu)以及它們之間相互關(guān)系撰洗,并對這種結(jié)構(gòu)定義相應(yīng)的運算,而且確保經(jīng)過這...
    Winterfell_Z閱讀 5,654評論 0 13
  • 文/向上 秋風(fēng)腐芍, 你帶著許多塵沙差导, 吹過我。 讓我的傷感被你帶走吧猪勇! 秋雨设褐, 你帶著許多苦淚, 淋過我泣刹。 讓我流出...
    A向上閱讀 1,797評論 32 77