1. 程式人生 > >leetcode 第105題(從前序與中序遍歷序列構造二叉樹) ,第106題(從中序與後序遍歷序列構造二叉樹)python解法(用時40ms)

leetcode 第105題(從前序與中序遍歷序列構造二叉樹) ,第106題(從中序與後序遍歷序列構造二叉樹)python解法(用時40ms)

leetcode 第105題(從前序與中序遍歷序列構造二叉樹) ,第106題(從中序與後序遍歷序列構造二叉樹)python解法(用時40ms)

先從105題開始:

第105題是利用前序和中序恢復二叉樹,主要還是應用遞迴的思想。
首先看一個簡單的例子,在如下樹中:
在這裡插入圖片描述
由於前序遍歷第一個數是父節點的值(1),所以將其構造成一個節點。接下來,在中序遍歷中找到這個值的索引(5),那麼這個索引將中序遍歷分成了兩個部分[9,8,4,2,5] , [11,10,6,3,7,12,13,14](題目中說樹中所有的值只出現一次,所以索引是唯一的)。在劃分的過程中要注意能否將中序切割成兩部分(因為可能是中序的第一個數或者最後一個數),如果只能切割成一部分,說明該父節點只有一個孩子。
切割成兩部分後,接下來就遞迴了,在遞迴時buildTree()函式的第二引數inorder即為切割開的中序遍歷的每個部分,而第一個引數preorder也要做出相應的改變。在中序遍歷中,在父節點1前面的五個數全部是左子樹的值,與前序遍歷1後面的五個數對應。所以左子樹的前序遍歷即為前序遍歷1後面的五位[2,4,8,9,5]。同樣,接下來的[3,6,10,11,7,12,13,14]為右子樹的前序遍歷。將這兩個前序遍歷分別作為遞迴函式的第一個引數。

上面的方法很常見,關鍵是怎樣去減少遞迴的次數。下面是我的方法,首先看第一種特殊情況,即整個樹只包含左子樹,如下圖。
在這裡插入圖片描述
從這裡可以看出,如果樹的節點全部為左節點,那麼它的中序遍歷和後序遍歷正好相反。
同樣如果整個樹只包含右節點,如下圖所示:
在這裡插入圖片描述
與全部為左節點的情況正好相反,此時中序遍歷和前序遍歷相同。

所以,接下來在構造樹的過程中,如果遇到這兩種情況,即中序遍歷和前序遍歷正好相同或正好相反時,就無需再向下遍歷,因為是全部左子樹或右子樹。而且這麼做有一個最大的好處,就是當整個樹只有左節點或右節點時,不需要遍歷,就能直接構造出整個樹。在這個題中最後一個測試用例就是這樣的,是一個節點特別多的,全部由左節點構成的樹,如果選擇遍歷,則會出現超時的情況。
下面是具體的程式碼,python實現。

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution(object):
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        if inorder:
            if inorder == preorder: # 全部為右節點
                temp = None
                for value in inorder[::-1]:
                    node = TreeNode(value)
                    node.right = temp
                    temp = node
                return temp
            if inorder == preorder[::-1]: # 全部為左節點
                temp = None
                for value in inorder:
                    node = TreeNode(value)
                    node.left = temp
                    temp = node
                return temp
            first = preorder[0]
            node = TreeNode(first)
            inorderIndex = inorder.index(first)
            if inorderIndex > 0:
                node.left = self.buildTree(preorder[1:inorderIndex+1], inorder[:inorderIndex])
            if inorderIndex < len(inorder)-1:
                node.right = self.buildTree(preorder[inorderIndex+1:], inorder[inorderIndex+1:])
            return node

這種方法通過了全部的測試用例,並用時40ms。

然後是106題:

106題是用後序與中序構造樹,與105題思路一樣,使用遞迴,然後判斷postorder與inorder的相等關係來減少遍歷次數(注意,這與105題切割的方法有一些不同,可以嘗試自己推一推)。下面是具體的程式碼:

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if inorder == postorder: # 全部為左節點
            temp = None
            for value in inorder:
                node = TreeNode(value)
                node.left = temp
                temp = node
            return temp
        elif inorder[::-1] == postorder: # 全部為右節點
            temp = None
            for value in postorder:
                node = TreeNode(value)
                node.right = temp
                temp = node
            return temp
        last = postorder[-1]
        node = TreeNode(last)
        inorderIndex = inorder.index(last)
        print(inorderIndex)
        if inorderIndex > 0:
            node.left = self.buildTree(inorder[:inorderIndex], postorder[:inorderIndex])
        if inorderIndex < len(inorder) - 1:
            node.right = self.buildTree(inorder[inorderIndex+1:], postorder[inorderIndex:len(postorder)-1])
        return node

也是隻是用40ms就完成了全部測試用例。

第一次寫部落格,有點緊髒,靴靴大家!!放一張老婆大人