wuyijia

导航

代码随想录算法训练营第十八天|513. 找树左下角的值、112. 路径总和、113. 路径总和 II、106. 从中序与后序遍历序列构造二叉树、105. 从前序与中序遍历序列构造二叉树

【参考链接】

513. 找树左下角的值

【注意】

1.用递归的话就就一直向左遍历,但是到最后一个,它未必是最后一行。是要找到树的最后一行的最左边的值。(不一定是指是左孩子)

2.如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。

3.只要是优先遍历左都可以,所以前中后序都可。

4.层序遍历只需要记录最后一行的第一个节点的数值即可。

【代码】

 1.递归遍历中,用一个变量存储最大深度。终止条件:遍历到叶子节点。然后比较当前叶子节点的深度是否比记录最大深度还大,大的话就要更新这个变量。result变量中存储遍历完树最后的最大深度。

2.向左遍历时先判断root.left是否为空,要有回溯过程,要不depth一直在增加,就出现错误。traversal(root.left,depth+1),隐藏回溯的过程在这个递归函数中,depth+1没有改变depth的值。

3.没有中的处理逻辑,只要强调左在右前面就行。

【代码】

 1 # Definition for a binary tree node.
 2 # class TreeNode(object):
 3 #     def __init__(self, val=0, left=None, right=None):
 4 #         self.val = val
 5 #         self.left = left
 6 #         self.right = right
 7 from collections import deque
 8 class Solution(object):
 9     def findBottomLeftValue(self, root):
10         """
11         :type root: TreeNode
12         :rtype: int
13         """
14     #     #1.递归法+回溯
15     #     self.max_depth = float('-inf')
16     #     self.result = None #最后左下角的值
17     #     self.traversal(root,0) #递归
18 
19     #     return self.result
20 
21     # def traversal(self, node, depth):
22     #     if not node.left and not node.right:#迭代终止条件:达到叶子节点
23     #         if depth > self.max_depth:
24     #             self.max_depth = depth
25     #             self.result = node.val #因为是先遍历最大深度的左节点所以保证result保存的是左下角的值
26     #         return
27 
28     #     #左
29     #     if node.left:#不为空时
30     #         depth += 1
31     #         self.traversal(node.left, depth)
32     #         depth -= 1#回溯
33     #     #右
34     #     if node.right:
35     #         depth += 1
36     #         self.traversal(node.right, depth)
37     #         depth -= 1
38           
39           #2.迭代法:队列 #测试用例[1,2,3,4,null,5,6,null,null,7]
40         queue = deque([root])
41         while queue:
42             size = len(queue) #1->2->3->1
43             leftmost = queue[0].val #1->2->4->7
44 
45             for i in range(size): #1->2->3
46                 node = queue.popleft() #1->2->3->4->5->6
47                 if node.left: #2->4->5->7
48                     queue.append(node.left) #2->34->45->67
49                 if node.right: #3->6
50                     queue.append(node.right) #23->456
51             if not queue:
52                 return leftmost #7

112. 路径总和

【注意】

1.本题前中后序都可以,无所谓,因为中节点也没有处理逻辑。

2.只要找到一条符合的路径就返回,返回true。参数直接传入目标值,做累减,知道叶子节点时为0,就是要求得的路径。

3.终止条件:遇到叶子节点进行判读是否为0.

【代码】

 1 # Definition for a binary tree node.
 2 # class TreeNode(object):
 3 #     def __init__(self, val=0, left=None, right=None):
 4 #         self.val = val
 5 #         self.left = left
 6 #         self.right = right
 7 class Solution(object):
 8     def hasPathSum(self, root, targetSum):
 9         """
10         :type root: TreeNode
11         :type targetSum: int
12         :rtype: bool
13         """
14         if not root:
15             return False
16         return self.traversal(root, targetSum) #递归
17     #1.递归+回溯
18     def traversal(self, node, count):
19         # 遇到叶子节点,并且计数为0
20         if not node.left and not node.right and count==0:
21             return True
22         if not node.left and not node.right and count!=0:
23             return False
24         
25         #
26         if node.left:
27             count -= node.left.val
28             if self.traversal(node.right, count):
29                 return True
30             count += node.left.val #回溯
31         #
32         if node.right: 
33             count -= node.right.val
34             if self.traversal(node.right, count): # 递归,处理节点
35                 return True
36             count += node.right.val # 回溯,撤销处理结果
37         
38         return False

113. 路径总和 II

【代码】

 1 # Definition for a binary tree node.
 2 # class TreeNode(object):
 3 #     def __init__(self, val=0, left=None, right=None):
 4 #         self.val = val
 5 #         self.left = left
 6 #         self.right = right
 7 class Solution(object):
 8     def __init__(self):
 9         self.result = []
10         self.path = []
11     #1.递归+回溯
12     def traversal(self, node, count):
13             if not node.left and not node.right and count == 0: # 遇到了叶子节点且找到了和为sum的路径
14                 self.result.append(self.path[:])
15                 return
16             if not node.left and not node.right and count != 0: # 遇到叶子节点而没有找到合适的边,直接返回
17                 return
18             #
19             if node.left:
20                 self.path.append(node.left.val)
21                 count -= node.left.val
22                 self.traversal(node.left, count)
23                 count += node.left.val#回溯
24                 self.path.pop()
25 
26             #
27             if node.right:
28                 self.path.append(node.right.val) 
29                 count -= node.right.val
30                 self.traversal(node.right, count) # 递归
31                 count += node.right.val # 回溯
32                 self.path.pop() # 回溯
33 
34     def pathSum(self, root, targetSum):
35         """
36         :type root: TreeNode
37         :type targetSum: int
38         :rtype: List[List[int]]
39         """
40         if not root:
41             return self.result
42         self.path.append(root.val)# 把根节点放进路径
43         self.traversal(root,targetSum-root.val)
44 
45         return  self.result

106. 从中序与后序遍历序列构造二叉树

【注意】

1.以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。

【代码】

说到一层一层切割,就应该想到了递归。

来看一下一共分几步:

  • 第一步:如果数组大小为零的话,说明是空节点了。

  • 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)

  • 第五步:切割后序数组,切成后序左数组和后序右数组

  • 第六步:递归处理左区间和右区间

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        # 第一步: 特殊情况讨论: 树为空. (递归终止条件)
        if not postorder:
            return None
        
        # 第二步: 后序遍历的最后一个就是当前的中间节点.
        root_val = postorder[-1]
        root = TreeNode(root_val) #根节点

        # 第三步: 找切割点.
        separator_idx = inorder.index(root_val)

        # 第四步: 切割inorder数组. 得到inorder数组的左,右半边. 左闭右开
        inorder_left = inorder[:separator_idx]
        inorder_right = inorder[separator_idx+1:]

        # 第五步: 切割postorder数组. 得到postorder数组的左,右半边.
        # ⭐️ 重点1: 中序数组大小一定跟后序数组大小是相同的.
        #左闭右开 右开包含下一个区间的一个值
        postorder_left = postorder[:len(inorder_left)] #控制大小一样,用len
        postorder_right = postorder[len(inorder_left):len(postorder)-1]

        # 第六步: 递归
        root.left = self.buildTree(inorder_left,postorder_left)
        root.right = self.buildTree(inorder_right,postorder_right)

        return root

105. 从前序与中序遍历序列构造二叉树

【代码】

 1 # Definition for a binary tree node.
 2 # class TreeNode(object):
 3 #     def __init__(self, val=0, left=None, right=None):
 4 #         self.val = val
 5 #         self.left = left
 6 #         self.right = right
 7 class Solution(object):
 8     def buildTree(self, preorder, inorder):
 9         """
10         :type preorder: List[int]
11         :type inorder: List[int]
12         :rtype: TreeNode
13         """
14         # 第一步: 特殊情况讨论: 树为空. 或者说是递归终止条件
15         if not preorder:
16             return None
17         
18         # 第二步: 前序遍历的第一个就是当前的中间节点.
19         root_val = preorder[0]
20         root =TreeNode(root_val)
21 
22         # 第三步: 找切割点.
23         separator_idx = inorder.index(root_val)
24 
25         # 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
26         inorder_left = inorder[:separator_idx]
27         inorder_right = inorder[separator_idx+1:]
28 
29         # 第五步: 切割preorder数组. 得到preorder数组的左,右半边.
30         # ⭐️ 重点1: 中序数组大小一定跟前序数组大小是相同的.
31         preorder_left = preorder[1:1+len(inorder_left)]
32         preorder_right = preorder[1+len(inorder_left):]
33 
34         # 第六步: 递归
35         root.left = self.buildTree(preorder_left,inorder_left)
36         root.right = self.buildTree(preorder_right,inorder_right)
37 
38         return root

 

posted on 2023-05-28 16:07  小吴要努力  阅读(14)  评论(0)    收藏  举报