1. 程式人生 > >劍指offer 二叉樹與二叉搜尋樹最佳解彙總 Python

劍指offer 二叉樹與二叉搜尋樹最佳解彙總 Python

面試題6: 重建二叉樹

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

思路:找出中間節點後,基於遞迴思想實現。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回構造的TreeNode根節點
    def reConstructBinaryTree(self, pre, tin):
        # 判斷前序遍歷和中序遍歷序列是否為空,為空就返回None
        if not pre or not tin:
           return None 
        # 因為pre為先序遍歷,pre中的第一個點為首節點
        root = TreeNode(pre[0])
        # 找到首節點在中序遍歷中的索引位置     
        pivot = tin.index(pre[0])
        # 對左右分別遞迴  如: [1|2,3,4||,5,6,7],[3,2,4|1|6,7]        
        root.left = self.reConstructBinaryTree(pre[1:pivot+1],tin[0:pivot])
        root.right = self.reConstructBinaryTree(pre[pivot+1:],tin[pivot+1:])  
        return root

面試題18:樹的子結構

輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)

思路:對於兩棵二叉樹來說,要判斷B是不是A的子結構,首先第一步在樹A中查詢與B根節點的值一樣的節點。 通常對於查詢樹中某一個節點,我們都是採用遞迴的方法來遍歷整棵樹。 第二步就是判斷樹A中以R為根節點的子樹是不是和樹B具有相同的結構。 這裡同樣利用到了遞迴的方法,如果節點R的值和樹的根節點不相同,則以R為根節點的子樹和樹B肯定不具有相同的節點; 如果它們值是相同的,則遞迴的判斷各自的左右節點的值是不是相同。 遞迴的終止條件是我們達到了樹A或者樹B的葉節點。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # 依題意,如果pRoot2為空,返回False
        if not pRoot1 or not pRoot2:
        	return False
        result = False
       # 三個遍歷方向
        # 如果說當前結點存放的元素相同,則直接往後遍歷
    	if pRoot1.val == pRoot2.val:
    		result = self.IsSubtree(pRoot1, pRoot2)
    	# 通過上面if語句的討論,result還是為False,pRoot1的左子樹繼續討論
    	if not result:
    		result = self.IsSubtree(pRoot1.left, pRoot2)
    	# 右子樹
    	if not result:
    		result = self.IsSubtree(pRoot1.right, pRoot2)
            return result
    
    def IsSubtree(self, p1, p2):
    	# p2如果遍歷完,則證明pRoot2是pRoot1的子結構,返回True
    	if not p2:
    		return True
    	# 如果說p1遍歷完,則證明p2還沒有匹配結束,返回False
    	if not p1:
    		return False
    	# 如果說結點元素不相等,則不能匹配
    	if p1.val != p2.val:
    		return False
    	return self.IsSubtree(p1.left, p2.left) and self.IsSubtree(p1.right, p2.right)

面試題19:二叉樹的映象

操作給定的二叉樹,將其變換為源二叉樹的映象。

二叉樹的映象定義:源二叉樹

8

/\

6 10

/ \/ \

57 9 11

映象二叉樹

8

/\

10 6

/ \/ \

11 9 7 5

思路:

由題目我們可以知道所謂二叉樹的映象無非就是不斷交換根結點的左右子樹(注意不是左右孩子,當然說左右孩子也對,但是每次遞迴的時候真正交換的是兩個子樹的頭結點+整棵子樹)。明白了原理,讓我們用遞迴實現吧!

1、我們知道我們要定義一個方法 Mirror ,這個方法的主要功能是實現整棵樹的交換,注意是整棵樹,而不是某顆子樹,為什麼這麼說,接下來便知道了。

2、首先我們肯定是交換根節點的左右子樹嘛!對了,交換完之後,你會發現,對於以根節點左孩子右孩子為根節點的兩棵子樹,也需要做同樣的事情,因此,為了不把程式碼寫得跟論文那麼長,我們決定用遞迴,自己呼叫自己的功能(想想它自己的功能是什麼?無非就是將以引數為頭結點的兩棵子樹交換嘛!),但傳入的引數為根節點的左孩子、右孩子了

3、由於是先序遍歷,所以呢!我們就先對左子樹進行遞迴,在遞迴右子樹

4、當2,3都執行完成,也就是我們的Mirror函式結束了,你會發現,這個Mirror函式實際操作的是整棵樹,但函式體我們很直觀理解的程式碼卻只有根節點左右子樹的交換的那部分程式碼(沒涉及遞迴的那部分),其他誰幫我們做了呢?沒錯,就是遞迴函式。

還有就是上面強調的Mirror這個大函式是對整棵大樹而言的,為什麼呢?因為這個函式的方法體,已經包含了幫你處理左右子樹的遞迴函數了!

最後,我不管你是看懂了還是沒看懂,我盡力了。對於遞迴的理解,就是某些相同的功能跟自己實現的功能一模一樣時,用遞迴,但要注意遞迴的終止條件哦!

class Solution:
    # 返回映象樹的根節點
    def Mirror(self, root):
        if not root:
            return 
        if root:
            # 用先序遍歷從根節點出發
            root.left,root.right = root.right,root.left
            self.Mirror(root.left)
            self.Mirror(root.right)

面試題25:二叉樹中和為某一值的路徑

輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。

思路:

class Solution:
    # 返回二維列表,內部每個列表表示找到的路徑
    def FindPath(self, root, expectNumber):
        if not root:
            return []
        if not root.left and not root.right and expectNumber == root.val: # 左右子孩子都是空,並且當前值等於expectNumber返回當前結點的值
            return [[root.val]]
        result = []
        left = self.FindPath(root.left, expectNumber - root.val)
        right = self.FindPath(root.right, expectNumber - root.val)
        for i in left+right:
            result.append([root.val]+i)
        return result

面試題39:二叉樹的深度

輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。

思路:

方法一:遞迴

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        if not pRoot:
            return 0
        left = self.TreeDepth(pRoot.left)
        right = self.TreeDepth(pRoot.right)
        return max(left+1,right+1)

方法二:非遞迴,層序遍歷

from collections import deque
def TreeDepth(self, pRoot):
    if not root:
        return
    depth = 0
    queue = deque([pRoot])
    last =pRoot
    while queue:
        current_node = queue.popleft()
        if current_node.left:
            queue.append(current_node.left)
        if current_node.right:
            queue.append(current_node.right)
        if current_node == last:
            depth+=1
            if queue:
                last = queue[-1]
    return depth

面試題58:二叉樹的下一個結點

給定一顆二叉樹和其中的一個結點,如何找出中序遍歷順序的下一個結點?樹中的結點除了有兩個分別指向左右子結點的指標以外,還有一個指向父節點的指標。

思路:

  1. 若該節點存在右子樹:則下一個節點為右子樹最左子節點(如圖節點B)
  2. 若該節點不存在右子樹:這時分兩種情況:

2.1該節點為父節點的左子節點,則下一個節點為其父節點(如圖節點D)

2.2該節點為父節點的右子節點,則沿著父節點向上遍歷,知道找到一個節點的父節點的左子節點為該節點,則該節點的父節點下一個節點(如圖節點I,沿著父節點一直向上查詢找到B(B為其父節點的左子節點),則B的父節點A為下一個節點)。

# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # 中序遍歷:左中右
        if not pNode:
            return None
        # 判斷當前結點有沒有右子樹,若存在右子樹,下一個結點就是右子樹的最左子結點
        if pNode.right:
            pNode = pNode.right # 進入到右子樹的父節點
            while pNode.left: # 不斷遍歷左結點
                pNode = pNode.left
            return pNode # 返回右子樹的最左子結點
        # 沒有右子樹就向上遍歷找到他的父親結點,如果他是父親結點的左孩子結點,下一個結點就是父親結點
        # 如果不是,就繼續向上找尋當前父親結點w的父親結點q,並判斷q是否為他的父親結點e的左孩子
        # 如此反覆直到找到匹配的情況,找不到就返回None
        while pNode.next:
            if pNode.next.left == pNode:
                return pNode.next
            pNode = pNode.next
        return None


面試題58:對稱的二叉樹

請實現一個函式,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的映象是同樣的,定義其為對稱的。

思路:

# -*- 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 not pRoot:
            return True
        return self.judge_helper(pRoot.left,pRoot.right)
        
    def judge_helper(self,left,right):
        if not left and not right: # 當left和right都為空時,返回True,跳出
            return True
        if not left or not right: # 當left和right有一邊為空時,返回False,跳出
            return False
        if left.val == right.val: # 判斷left和right的val是否相等,相等就繼續遞迴判斷應該對成的兩個點是否對稱
            return self.judge_helper(left.left,right.right) and self.judge_helper(left.right,right.left)
        return False

面試題60:把二叉樹列印成多行

從上到下按層列印二叉樹,同一層結點從左至右輸出。每一層輸出一行。

思路:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
from collections import deque
class Solution:
    # 返回二維列表[[1,2],[4,5]]
    def Print(self, pRoot):
        if not pRoot:
            return[]
        res = [] # res列表用於記錄最終結果
        tmp = [] # 用於每一層結點的快取
        last = pRoot # 定義last結點表示下一層的最末結點
        next_level = deque([pRoot]) # 初始化下一行結點的佇列,起始位為根結點[pRoot]
        while next_level: # 當下一行有結點時
            current_node = next_level.popleft() # 取出下一行結點最左邊的結點
            tmp.append(current_node.val) # 將最左邊的值放入tmp
            if current_node.left: # 如果當前結點有左孩子
                next_level.append(current_node.left) # 在佇列右側新增該左孩子結點
            if current_node.right: # 如果當前結點有右孩子
                next_level.append(current_node.right) # 在佇列右側新增該右孩子結點
            if current_node == last: # 若當前結點正好是下一行結點的最後一個位置
                res.append(tmp) # 給結果增添上tmp,也就是當前行的所有結點
                tmp = [] # 清空tmp
                if next_level: # 如果還有下一層
                    last = next_level[-1] # 令last等於末尾項
        return res

面試題61:按之字形順序列印二叉樹

請實現一個函式按照之字形列印二叉樹,即第一行按照從左到右的順序列印,第二層按照從右至左的順序列印,第三行按照從左到右的順序列印,其他行以此類推。

思路:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
from collections import deque
class Solution:
    def Print(self, pRoot):
        if not pRoot:
            return []
        result = []
        tmp = []
        last = pRoot #記錄每層的最後一個結點,方便層序遍歷換行
        left_to_right = True
        next_level_node_LtoR = deque([pRoot]) #初始化下一層所有節點的佇列,起初為只有根結點
        while next_level_node_LtoR: #當下一層不為空時
            current_node = next_level_node_LtoR.popleft() #不停從下層佇列左邊彈出
            tmp.append(current_node.val) #將彈出結點放入tmp中
            if current_node.left:
                next_level_node_LtoR.append(current_node.left)
            if current_node.right:
                next_level_node_LtoR.append(current_node.right)
            if current_node == last: #當執行到最後一個結點,給result賦值當前行的所有元素,也就是tmp
                if left_to_right: 
                    result.append(tmp)
                else: #若該行應該為從右到左,則倒序append
                    result.append(tmp[::-1])
                tmp = [] #清空tmp,以便下一層繼續使用
                left_to_right = not left_to_right #調整此項,顛倒下一行的輸出順序
                if next_level_node_LtoR: #更新下一行的last結點,如果下一行已經沒有元素就會退出
                    last = next_level_node_LtoR[-1]
        return result

面試題62:序列化二叉樹

請實現兩個函式,分別用來序列化和反序列化二叉樹

思路:也可以用層序遍歷

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    index = -1
    def Serialize(self, root):
        if root == None:
            return '#'
        return str(root.val) + ',' + self.Serialize(root.left) + ',' + self.Serialize(root.right)
        # return形如s = '5,#,#,6'
        
    def Deserialize(self, s):
        self.index += 1 #每次遞迴給index+1去到下一個字元
        l = s.split(',')
        if self.index >= len(s):
            return None
        root = None
        if l[self.index] != '#':
            root = TreeNode(int(l[self.index]))
            root.left = self.Deserialize(s) # 對當前結點的左右結點遞迴
            root.right = self.Deserialize(s)
        return root

面試題:平衡二叉樹

輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。

思路:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        if not pRoot:
            return True 
        # 對左右兩邊同時遞迴
        if abs(self.Tree_depth(pRoot.left) - self.Tree_depth(pRoot.right)) > 1:
            return False
        return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)

    def Tree_depth(self,pRoot):
        if not pRoot:
            return 0
        # 二叉樹的後序遍歷
        left = self.Tree_depth(pRoot.left)
        right = self.Tree_depth(pRoot.right)
        return max(left+1,right+1) # 返回當前樹深











相關推薦

offer刷題記錄26——搜尋雙向連結串列

題目描述 輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。 public class Solution { public TreeNode Convert(TreeNode root) {

offer 搜尋最佳彙總 Python

面試題6: 重建二叉樹 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷

Offer面試題:25.搜尋雙向連結串列

一、題目:二叉搜尋樹與雙向連結串列 題目:輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。比如輸入下圖中左邊的二叉搜尋樹,則輸出轉換之後的排序雙向連結串列。   二叉搜尋樹的節點定義如下,這裡使用C#語言描述:

offer》面試題39 的深度(java)

設計模式 博客 rgs 歷史 存在 復制 pri 取值 今天 摘要: 今天翻到了《劍指offer》面試題39,題目二中的解法二是在函數的參數列表中通過指針的方式進行傳值,而java是沒有指針的,所以函數要進行改造。然而我翻了下別人的java版本(我就想看看有什麽高大上的改造

offer三十八之的深度

ret terminal pro roo 結點 路徑 splay close solution 一、題目   輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。 二、思路   遞歸,詳見代碼。 三、代碼

offer】7、重建

nbsp treenode truct 遞歸函數 tar end || 部分 遍歷 題目 給出二叉樹的前序遍歷與中序遍歷結果,重建該二叉樹。 思路 由於前序遍歷的第一個數字是根節點,將中序遍歷分為左右子樹兩個部分。接下來就遞歸,將左子樹和右子樹的序列分離出來,然後調用遞歸函

Offer】操作給定的,將其變換為源的鏡像。

right 鏡像 tree style turn val 交換 實現 oot 二叉樹的鏡像定義:源二叉樹 8 / \ 6 10 / \ / \ 5 7 9 11 鏡像二叉樹 8

offer 面試題8:的下一個節點 c++

題目:給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指標。 解析:三種情況:1.若節點有右子樹,中序下一個就是 右子樹最左孩子節點  2.若無右子樹,且當前節點是父節點的左子節點,下一個就是父節點 &nb

offer 28: 對稱的(遞迴實現)

題目 實現一個函式,用來判斷一棵二叉樹是不是對稱的。如果一顆二叉樹和它的映象一樣那麼它對稱。 分析 存在三種遍歷演算法,前序遍歷,中序遍歷,後序遍歷。我們可以針對前序遍歷定義一種對稱的遍歷演算法。即先遍歷父節點,再遍歷右結點,最後遍歷左結點。 以

offer】之字形列印python

題目描述 請實現一個函式按照之字形列印二叉樹,即第一行按照從左到右的順序列印,第二層按照從右至左的順序列印,第三行按照從左到右的順序列印,其他行以此類推。 在上一篇部落格中:層次遍歷,每一層在一行輸出中,只需要將奇數行的result反轉一下就行了 另外一種方法就是,需要反轉佇列的結果,

offer——(8)重建&&的深度

/** * Definition for binary tree * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x)

offer:輸入一棵,判斷該是否是平衡

輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。 //後續遍歷二叉樹,遍歷過程中求子樹高度,判斷是否平衡 class Solution { public: bool IsBalanced(TreeNode *root, int & dep){

offer{面試題25:中和為某一值的路徑}

思路:這道題比較有意思,類似的題我在面試裡經常遇到過,圍繞著樹的深度遍歷和廣度遍歷做文章,針對這種型別的題,大家更多考慮的解決方案是遞迴,說白了二叉樹就是一群小二叉樹,上次做寶寶樹的筆試題的時候,出的演算法題就是求任意兩個節點之間的最遠距離,說白了還是遍歷的問題,回到這道題  &n

offer{面試題24:搜尋的後序遍歷序列}

這個題似曾相識,之前劍指offer有一道題是判斷該子樹是否是樹的一部分,有異曲同工之妙,看到這種題,上倆就應該想遞迴。 public class Solution { public boolean VerifySquenceOfBST(int [] sequence) {

牛客網線上程式設計專題《offer-面試題39》的深度

題目連結: 題目描述: 解題思路: 解法:遞迴的遍歷一棵數的左右子樹。 已經AC的程式碼: public class treeDepth39 { public class Tr

offer面試題八:的下一個節點

題目描述: 給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指標。 思路 1.若該節點存在右子樹:則下一個節點為右子樹最左子節點(如圖節點 B ) 2. 若該節點不存在右子樹:這時分兩

offer面試題7:重建(java實現)

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹,假設輸入的前序遍歷和中序遍歷的結果都不含重複的數字。例如:輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}則重建二叉樹:其中二叉樹的定義如下:  * publi

offer{面試題19 :的映象}

public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) {

Offer面試題6 重建

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入的前序遍歷序列{1,2,4,7,3,5,6,8}和後序遍歷序列{4,7,2,1,5,3,8,6},則重建出如圖所示的二叉樹 二叉樹結點定義如下:

offer{4-6}】重建、用兩個棧實現佇列、旋轉陣列的最小數字

重建二叉樹、用兩個棧實現佇列、旋轉陣列的最小數字重建二叉樹題目描述C++程式碼題目描述C++程式碼題目描述C++程式碼 重建二叉樹 題目描述 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹