Day 18 二叉樹:513. 底層左下角, 112|113. 路徑總和I II, 106. 中序|后序構造, 105. 前序|中序構造

513. 找樹左下角的值

  • 思路
    • example
    • 迭代盘榨,層序遍歷bfs ,最后一層第一個節(jié)點蟆融。
  • 復雜度. 時間:O(n), 空間: O(n)
class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        que = collections.deque()
        res = -1
        if root:
            que.append(root)
        while que:
            size = len(que)
            for i in range(size):
                node = que.popleft()
                if i == 0:
                    if node.left == None and node.right == None:
                        res = node.val 
                if node.left:
                    que.append(node.left) 
                if node.right:
                    que.append(node.right) 
        return res  
class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        que = collections.deque()
        res = -1
        if root:
            que.append(root)
        while que:
            size = len(que)
            for i in range(size):
                node = que.popleft()
                if i == 0:
                    res = node.val 
                if node.left:
                    que.append(node.left)
                if node.right:
                    que.append(node.right) 
        return res 
  • 遞歸草巡,前序(自上而下), dfs, 回溯
    • 左下角:
      - 葉子:node的children 為空
      • 最下一層最左葉子: 利用depth 來判斷是否最下一層, 前序遍歷保證了第一個更新depth的節(jié)點為最左葉子型酥。
class Solution:
    def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
        def traversal(root, depth):
            nonlocal max_depth, res
            if root.left == None and root.right == None:
                if depth > max_depth:
                    max_depth = depth 
                    res = root.val
                    return 
            if root.left:
                depth += 1
                traversal(root.left, depth)
                depth -= 1
            if root.right:
                depth += 1
                traversal(root.right, depth)
                depth -= 1
        max_depth= -float('inf')
        res = -float('inf')
        traversal(root, 1)
        return res

112. 路徑總和

  • 思路
    • example
    • 給你二叉樹的根節(jié)點 root 和一個表示目標和的整數(shù) targetSum 山憨。判斷該樹中是否存在 根節(jié)點到葉子節(jié)點 的路徑查乒,這條路徑上所有節(jié)點值相加等于目標和 targetSum 。如果存在郁竟,返回 true 玛迄;否則,返回 false 棚亩。
    • 遞歸蓖议,前序,回溯
      • 遞歸函數(shù)傳遞參數(shù)pathsum讥蟆,返回值 True or False勒虾,方便提早退出遍歷。
      • 也可以維護當前path與targetsumr的差值瘸彤。
  • 復雜度. 時間:O(n), 空間: O(n)
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        def traversal(root, pathsum):
            if root.left == None and root.right == None:
                if pathsum == targetSum:
                    return True
                else: 
                    return False
            if root.left: 
                pathsum += root.left.val
                flag = traversal(root.left, pathsum)
                if flag:
                    return True
                pathsum -= root.left.val
            if root.right:
                pathsum += root.right.val
                flag = traversal(root.right, pathsum)
                if flag:
                    return True
                pathsum -= root.right.val
            return False 
        if root == None:
            return False
        return traversal(root, root.val)
  • 回溯框架比較方便
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        def traversal(root, pathSum):
            if root.left == None and root.right == None:
                if pathSum == targetSum:
                    return True 
                else:
                    return False 
            if root.left:
                flag = traversal(root.left, pathSum + root.left.val) 
                if flag:
                    return True  
            if root.right:
                flag = traversal(root.right, pathSum + root.right.val)  
                if flag:
                    return True 
            return False 
        if root == None:
            return False  
        return traversal(root, root.val)
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        def traverse(root):
            nonlocal pathSum 
            if root.left == None and root.right == None:
                if pathSum == targetSum:
                    return True  
                else:
                    return False  
            if root.left:
                pathSum += root.left.val 
                if traverse(root.left):
                    return True  
                pathSum -= root.left.val 
                # return False  # !!!
            if root.right:
                pathSum += root.right.val 
                if traverse(root.right):
                    return True  
                pathSum -= root.right.val 
            return False  # !!!
        if root == None:
            return False  
        pathSum = root.val 
        return traverse(root)  
  • DFS框架要注意在base case返回值進行“撤銷”操作从撼。
class Solution:
    def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
        def traversal(root):
            nonlocal pathSum
            if root == None:
                return False 
            pathSum += root.val 
            if root.left == None and root.right == None:
                if pathSum == targetSum:
                    pathSum -= root.val 
                    return True 
                else:
                    pathSum -= root.val # !!!
                    return False 
            valid_left = traversal(root.left)
            if valid_left:
                return True 
            valid_right = traversal(root.right) 
            if valid_right:
                return True 
            pathSum -= root.val
            return False  
        pathSum = 0
        return traversal(root)
  • 遞歸,后序, 自下而上
    • 比較不自然钧栖。
TBA
  • 迭代,層序遍歷
    • 入deque的時候把當前pathsum也加進去婆翔。
    • 每一層popleft()出來node的時候判斷是否葉子節(jié)點拯杠。若是,則比較pathsum 和 targetsum.
TBA

113. 路徑總和 II

  • 思路
    • example
    • 類似上題啃奴,這里要找出所有可行答案潭陪。
    • 回溯框架
  • 復雜度. 時間:O(n), 空間: O(n)
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        def traversal(root, pathsum):
            if root.left == None and root.right == None:
                if pathsum == targetSum:
                    res.append(path[:])
                    return
            if root.left: 
                pathsum += root.left.val
                path.append(root.left.val)
                traversal(root.left, pathsum)
                path.pop()
                pathsum -= root.left.val
            if root.right:
                pathsum += root.right.val
                path.append(root.right.val)
                traversal(root.right, pathsum)
                path.pop()
                pathsum -= root.right.val
        if root == None:
            return []
        res, path = [], [root.val]
        traversal(root, root.val)
        return res
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        def traversal(root, path):
            if root.left == None and root.right == None:
                if sum(path) == targetSum:
                    res.append(path[:])
                    return 
            if root.left: 
                path.append(root.left.val) 
                traversal(root.left, path)
                path.pop()
            if root.right:
                path.append(root.right.val) 
                traversal(root.right, path)
                path.pop() 
        res = []
        if root == None:
            return res 
        path = [root.val]
        traversal(root, path)
        return res   
class Solution:
    def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
        def traversal(root, pathSum):
            if root.left == None and root.right == None:
                if pathSum == targetSum:
                    res.append(path[:])
                return 
            if root.left:
                path.append(root.left.val)
                traversal(root.left, pathSum+root.left.val) 
                path.pop()
            if root.right:
                path.append(root.right.val)
                traversal(root.right, pathSum+root.right.val)
                path.pop()  
        if root == None:
            return []
        res = []
        path = [] 
        path.append(root.val) 
        traversal(root, root.val)
        return res 

106. 從中序與后序遍歷序列構造二叉樹

  • 思路
    • example
    • 樹中每個node的值都不同,這樣可以用值唯一確定node.
    • 遞歸構造樹最蕾。找出并建立樹的根節(jié)點依溯,然后劃分inorder和postorder數(shù)組,遞歸構造左子樹和右子樹瘟则,并且鏈接起來黎炉。這里的關鍵是找出切割位置(根節(jié)點),并且劃分左子樹和右子樹對應的兩個子數(shù)組醋拧。
      • 構造樹(假設是最基本的三個元素的滿樹):先建立根節(jié)點慷嗜。然后處理左節(jié)點和右節(jié)點前且鏈接起來。
      • 例子:

        inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
        • postorder(左右中)最右邊即為根節(jié)點
        • inorder(左中右)需要線性掃描找到pivot位置丹壕,pivot左邊是左子樹 [9]庆械,pivot右邊是右子樹 [15,20,7]
        • postorder左子樹取inorder左子樹相同size即可 [9],postorder右子樹同理 [15,20,7]菌赖。
        • 注意指標的取值范圍缭乘。
      • 遞歸函數(shù):參數(shù)為 當前節(jié)點,inorder, postorder琉用。
      • 基本case: 注意有可能左或右子樹可能為空堕绩, 所以要處理[]情況策幼。
      • 返回值:根節(jié)點
  • 復雜度. 時間:O(n)?, 空間: O(n)
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        # len(inorder) == len(postorder)
        # Base Case
        if postorder == []:
            return None
        val = postorder[-1] # 根節(jié)點數(shù)值
        root = TreeNode(val) # 建立節(jié)點
        # Find pivot in inorder 
        pivot = 0
        for i in range(len(inorder)):
            if inorder[i] == val:
                pivot = i
                break 
        # partition inorder and postorder
        # 左中右
        # 左右中
        inorder_left, inorder_right = inorder[:pivot], inorder[pivot+1:]
        size_left, size_right = len(inorder_left), len(inorder_right)
        postorder_left, postorder_right = postorder[:size_left], postorder[size_left : size_left+size_right]
        # recursive and link
        root.left = self.buildTree(inorder_left, postorder_left)
        root.right = self.buildTree(inorder_right, postorder_right)
        return root
  • 可以“優(yōu)化”,傳遞inorder和postorder數(shù)組的start,end指標來確定左右子樹逛尚。
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        def traversal(start1, end1, start2, end2): # 1: inorder, 2: postorder 
            if start1 > end1:
                return None 
            root_val = postorder[end2]
            root = TreeNode(root_val) 
            # 分割
            pivot_idx = 0
            while pivot_idx <= end1: 
                if inorder[pivot_idx] == root.val:
                    break 
                pivot_idx += 1
            left_size = pivot_idx - start1
            root.left = traversal(start1, pivot_idx-1, start2, start2+left_size-1)
            root.right = traversal(pivot_idx+1, end1, start2+left_size, end2-1)
            return root 
        n = len(inorder)
        return traversal(0, n-1, 0, n-1)
  • 這個更簡潔
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        def build(inorder, postorder): 
            n = len(inorder)
            if n == 0:
                return None 
            root = TreeNode(postorder[-1]) 
            val = postorder[-1]
            idx = -1
            for i in range(n):
                if inorder[i] == val:
                    idx = i
                    break 
            root.left = build(inorder[0:idx], postorder[0:idx])
            root.right = build(inorder[idx+1:n], postorder[idx:n-1])
            return root 
        return build(inorder, postorder) 
class Solution:
    def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
        n = len(inorder)
        if n == 0:
            return None
        val = postorder[-1]
        root = TreeNode(val, None, None) 
        idx = 0
        while idx < n:
            if inorder[idx] == val:
                break  
            idx += 1 # !!!
        root.left = self.buildTree(inorder[:idx], postorder[:idx]) 
        root.right = self.buildTree(inorder[idx+1:], postorder[idx:n-1])
        return root   

105. 從前序與中序遍歷序列構造二叉樹

  • 思路
    • example
    • 三生萬物垄惧,左中右的輪回
    • 前后
    • 遞歸主體思路
      • 建立節(jié)點
      • 劃分兩個數(shù)組,分別得到左右子樹
      • 遞歸調用建立左右子樹绰寞,鏈接
    • 遞歸函數(shù)傳遞參數(shù): inorder, postorder 數(shù)組
    • 基本case: 空節(jié)點
    • 返回值:當前根節(jié)點
  • 復雜度. 時間:O(n), 空間: O(n)
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        #  preorder: 中左右
        #  inorder : 左中右
        # Base Case
        if len(preorder) == 0:
            return None 
        val = preorder[0]
        root = TreeNode(val)
        # find pivot index in inorder 
        pivot = 0
        for i in range(len(inorder)):
            if inorder[i] == val:
                pivot = i 
                break 
        # partition 
        inorder_left, inorder_right = inorder[:pivot], inorder[pivot+1:]
        size_left, size_right = len(inorder_left), len(inorder_right)
        preorder_left, preorder_right = preorder[1:1+size_left], preorder[1+size_left:]
        # recursive, link
        root.left = self.buildTree(preorder_left, inorder_left)
        root.right = self.buildTree(preorder_right, inorder_right)
        return root
class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        n = len(inorder)
        if n == 0:
            return None 
        root = TreeNode(preorder[0])
        val = preorder[0]
        idx = -1
        for i in range(n):
            if inorder[i] == val:
                idx = i 
                break 
        root.left = self.buildTree(preorder[1:idx+1], inorder[0:idx])
        root.right = self.buildTree(preorder[idx+1:n], inorder[idx+1:n])
        return root 
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末到逊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子滤钱,更是在濱河造成了極大的恐慌觉壶,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件件缸,死亡現(xiàn)場離奇詭異铜靶,居然都是意外死亡,警方通過查閱死者的電腦和手機他炊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進店門争剿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人痊末,你說我怎么就攤上這事蚕苇。” “怎么了凿叠?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵涩笤,是天一觀的道長。 經常有香客問我盒件,道長蹬碧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任炒刁,我火速辦了婚禮恩沽,結果婚禮上,老公的妹妹穿的比我還像新娘切心。我一直安慰自己飒筑,他們只是感情好,可當我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布绽昏。 她就那樣靜靜地躺著协屡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪全谤。 梳的紋絲不亂的頭發(fā)上肤晓,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天,我揣著相機與錄音,去河邊找鬼补憾。 笑死漫萄,一個胖子當著我的面吹牛,可吹牛的內容都是我干的盈匾。 我是一名探鬼主播腾务,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼削饵!你這毒婦竟也來了岩瘦?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤窿撬,失蹤者是張志新(化名)和其女友劉穎启昧,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劈伴,經...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡密末,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了跛璧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片严里。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖追城,靈堂內的尸體忽然破棺而出田炭,到底是詐尸還是另有隱情,我是刑警寧澤漓柑,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站叨吮,受9級特大地震影響辆布,放射性物質發(fā)生泄漏。R本人自食惡果不足惜茶鉴,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一锋玲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涵叮,春花似錦惭蹂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至舀瓢,卻和暖如春廷雅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工航缀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留商架,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓芥玉,卻偏偏與公主長得像蛇摸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子灿巧,可洞房花燭夜當晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內容