LeetCodeCampsDay16
记录下,今儿三个题目一次过;
其中路径总和问题 和之前求二叉树的所有路径相似
找树左下角的值可以用层序解决
从中序与后序遍历序列构造二叉树 可以用递归方法,找到输入输出;终止条件;单层逻辑 就能解决
找树左下角的值
https://leetcode.cn/problems/find-bottom-left-tree-value/
给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 1:
1 2 输入: root = [2,1,3] 输出: 1
示例 2:
1 2 输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7
提示:
二叉树的节点个数的范围是 [1,104]
-231 <= Node.val <= 231 - 1
层序迭代思路
使用迭代–层序的方法, 令res存储每层第一个元素,遍历到最后一层结束,再返回res即可
层序迭代代码
时间复杂度O(N)
空间复杂度O(W)—二叉树最大宽度(也即二叉树每层最大长度)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution : def findBottomLeftValue (self, root: Optional [TreeNode] ) -> int : from collections import deque que = deque() if not root: return que.append(root) while que: L = len (que) level = None for i in range (L): node = que.popleft() if i ==0 : level = node.val if node.left: que.append(node.left) if node.right: que.append(node.right) return level
112. 路径总和
https://leetcode.cn/problems/path-sum/
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点。
示例 1:
1 2 3 输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true 解释:等于目标和的根节点到叶节点路径如上图所示。
示例 2:
1 2 3 4 5 6 输入:root = [1,2,3], targetSum = 5 输出:false 解释:树中存在两条根节点到叶子节点的路径: (1 --> 2): 和为 3 (1 --> 3): 和为 4 不存在 sum = 5 的根节点到叶子节点的路径。
示例 3:
1 2 3 输入:root = [], targetSum = 0 输出:false 解释:由于树是空的,所以不存在根节点到叶子节点的路径。
提示:
树中节点的数目在范围 [0, 5000]
内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
后序迭代思路
这题目和“二叉树所有路径 ”(day15)相似,只是将保存路径变成保存路径上所有元素的和
;遇到叶子节点时,判断这和是否与target相等即可
本题同样对前/中/后,甚至逆向的前/中/后顺序不敏感,所有顺序都能通过
下面代码使用后序
后序迭代代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution : def hasPathSum (self, root: Optional [TreeNode], targetSum: int ) -> bool : stack = list () path = list () if not root: return False stack.append(root) path.append(root.val) while stack: node = stack.pop() pathNode = path.pop() if not node.left and not node.right: if pathNode == targetSum: return True if node.right: stack.append(node.right) path.append(pathNode + node.right.val) if node.left: stack.append(node.left) path.append(pathNode + node.left.val) return False
递归思路
输入输出:输入节点和targetSum,这里的targetSum每次都需要变小; 输出True/False
终止条件:不能是判断node是否为空,因为它说明不了什么;需要判断是否为叶子节点,并且判断targetSum是否为零,为零则返回True;如果叶子节点且targetSum不为零,返回False
单层逻辑,判断左、右子树是否已经存在了满足target的路径,存在就返回True
递归代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution : def foo (self, node: TreeNode, targetSum: int ) -> bool : if not node.left and not node.right and 0 == targetSum: return True if not node.left and not node.right: return False if node.left: if self.foo(node.left, targetSum - node.left.val): return True if node.right: if self.foo(node.right, targetSum - node.right.val): return True return False def hasPathSum (self, root: Optional [TreeNode], targetSum: int ) -> bool : if not root: return False return self.foo(root, targetSum)
113. 路径总和 II
https://leetcode.cn/problems/path-sum-ii/
给你二叉树的根节点 root
和一个整数目标和 targetSum
,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例 1:
1 2 输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22 输出:[[5,4,11,2],[5,8,4,5]]
示例 2:
1 2 输入:root = [1,2,3], targetSum = 5 输出:[]
示例 3:
1 2 输入:root = [1,2], targetSum = 0 输出:[]
提示:
树中节点总数在范围 [0, 5000]
内
-1000 <= Node.val <= 1000
-1000 <= targetSum <= 1000
思路
和之前做的差不多,但注意,这里是将pathNode + [node.right.val]
传进去path里,所以对pathNode本身没有修改,如果直接修改pathNode,会把所有路径的值都添加进去,就不对了
迭代代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution : def pathSum (self, root: Optional [TreeNode], targetSum: int ) -> List [List [int ]]: stack = list () path = list () res = list () if not root: return [] stack.append(root) path.append([root.val]) while stack: node = stack.pop() pathNode = path.pop() if not node.left and not node.right: if sum (pathNode) == targetSum: res.append(pathNode) if node.right: stack.append(node.right) path.append(pathNode + [node.right.val]) if node.left: stack.append(node.left) path.append(pathNode + [node.left.val]) return res
递归代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution : def __init__ (self ): self.res = list () self.path = list () def foo (self, node: TreeNode, targetSum: int ): if not node.left and not node.right and targetSum == 0 : print (self.res, self.path, ) self.res.append(self.path[:]) return if not node.left and not node.right: return if node.left: self.path.append(node.left.val) self.foo(node.left, targetSum - node.left.val) self.path.pop() if node.right: self.path.append(node.right.val) self.foo(node.right, targetSum - node.right.val) self.path.pop() return def pathSum (self, root: Optional [TreeNode], targetSum: int ) -> List [List [int ]]: self.res.clear() self.path.clear() if not root: return self.res self.path.append(root.val) self.foo(root, targetSum - root.val) return self.res
106. 从中序与后序遍历序列构造二叉树
https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
示例 1:
1 2 输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
示例 2:
1 2 输入:inorder = [-1], postorder = [-1] 输出:[-1]
提示:
1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder
和 postorder
都由 不同 的值组成
postorder
中每一个值都在 inorder
中
inorder
保证 是树的中序遍历
postorder
保证 是树的后序遍历
递归思路
用两个指针,一个指针指向inorder首,一个指向postorder末尾
使用while循环,当left.val == right.val时
右子树
left的下标也是右子树的postorder的开始下标
right - 1的下标是右子树postorder的结束下标(注意python里列表的右是开区间,所以写postorder[left: right]即可)
left + 1 是inorder中右子树开始下标,并且后面全是右子树
左子树
left 是inorder中左子树结束下标,并且前面全是左子树
left 是postorder中左子树结束下标,并且前面全是左子树
把左子树想成一大块儿;右子树想成一大块儿,就好理解了
in
左子树
左子树
3
右子树
右子树
右子树
Post
左子树
左子树
右子树
右子树
右子树
3
left
Right
这是对于3的两个子树的区间位置
1 2 leftTree = self.foo(inorder[:left], postorder[:left]) rightTree = self.foo(inorder[left + 1 :], postorder[left: right])
递归代码
时间复杂度O(N^2)—最好情况O(NlogN)
空间复杂度O(N^2)
可以将while找root替换成index函数,即left = inorder.index(postorder[right])
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution : def foo (self, inorder: List [int ], postorder: List [int ] ) -> TreeNode: if len (inorder) == 0 : return None left = 0 right = len (postorder) - 1 while inorder[left] != postorder[right]: left += 1 leftTree = self.foo(inorder[:left], postorder[:left]) rightTree = self.foo(inorder[left + 1 :], postorder[left: right]) node = TreeNode(inorder[left]) node.left = leftTree node.right = rightTree return node def buildTree (self, inorder: List [int ], postorder: List [int ] ) -> Optional [TreeNode]: return self.foo(inorder, postorder)
105. 从前序与中序遍历序列构造二叉树
https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
给定两个整数数组 preorder
和 inorder
,其中 preorder
是二叉树的先序遍历 , inorder
是同一棵树的中序遍历 ,请构造二叉树并返回其根节点。
示例 1:
1 2 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]
示例 2:
1 2 输入: preorder = [-1], inorder = [-1] 输出: [-1]
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder
和 inorder
均 无重复 元素
inorder
均出现在 preorder
preorder
保证 为二叉树的前序遍历序列
inorder
保证 为二叉树的中序遍历序列
代码
时间复杂度O(N)—最好情况O(logN)
空间复杂度O(N)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution : def foo (self, preorder: List [int ], inorder: List [int ] ) -> TreeNode: if len (preorder) == 0 : return None left = 0 right = inorder.index(preorder[left]) leftTree = self.foo(preorder[left + 1 : right + 1 ], inorder[:right]) rightTree = self.foo(preorder[right + 1 :], inorder[right + 1 :]) root = TreeNode(preorder[left]) root.left = leftTree root.right = rightTree return root def buildTree (self, preorder: List [int ], inorder: List [int ] ) -> Optional [TreeNode]: return self.foo(preorder, inorder)