文章目录
二叉树的中序遍历(94E)
难度:【简单】
方法一:递归
树本身就有递归的特性,因此递归方法最简单,这里直接放上代码,需要说明的是,中序遍历,前序遍历和后序遍历可采用相同的代码模板完成实现。
代码如下:
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)
时间复杂度:O(n),n 为树的节点个数
空间复杂度:O(h),h 为树的高度
方法二:迭代
需要一个栈的空间,先用指针找到每颗子树的最左下角,然后进行进出栈的操作。
代码如下:
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = []
res = []
cur = root
while stack or cur:
while cur:
stack.append(cur)
cur = cur.left
cur = stack.pop()
res.append(cur.val)
cur = cur.right
return res
时间复杂度:O(n),n 为树的节点个数
空间复杂度:O(h),h 为树的高度
验证二叉搜索树(98M)
难度:【中等】
思路一:递归中序遍历,判断其是否升序且无重复值。
判断方法:order == list(sorted(set(order)))
代码如下:
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
inorder = self.inorder(root)
return inorder == list(sorted(set(inorder)))
def inorder(self,root):
if not root:
return []
return self.inorder(root.left) + [root.val] + self.inorder(root.right)
思路二:迭代中序遍历,在遍历过程中判断前序节点是否小于当前节点。
代码如下:
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
stack= []
pre = None
cur = root
while cur or stack:
while cur:
stack.append(cur)
cur = cur.left
cur = stack.pop()
if pre and pre.val >= cur.val:
return False
pre = cur
cur = cur.right
return True
思路三:递归中序遍历,在递归过程中判断前序节点是否小于当前节点。
代码如下:
class Solution:
def isValidBST(self, root: TreeNode) -> bool:
self.pre = None
def isBST(root):
if not root:
return True
if not isBST(root.left):
return False
if self.pre and self.pre.val >= root.val:
return False
self.pre = root
#print(root.val)
return isBST(root.right)
return isBST(root)
二叉树的层序遍历(102M)
102. 二叉树的层序遍历
难度:【中等】
参考:
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/python3-er-cha-shu-ceng-xu-bian-li-by-jo-nlx3/
思路:BFS
1、如果 root 为空,直接返回 [ ]
2、定义一个数组queue,并将 root 添加到 queue中,再定义一个res 数组保存结果
3、遍历 当前层 queue 的每个左子节点,右子节点,入队列,且要把 queue 更新成当前层的孩子节点列表,直到 queue 为空。
代码如下:
class Solution:
def levelOrder(self, root: TreeNode) -> List[List[int]]:
if not root:
return []
queue = [root]
res = []
while queue:
res.append([node.val for node in queue])
l1 = []
for node in queue:
if node.left:
l1.append(node.left)
if node.right:
l1.append(node.right)
queue = l1
return res
从前序与中序遍历序列构造二叉树(105M)
难度:【中等】
该题还未深入研究。
代码:
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
def myBuildTree(preorder_left: int, preorder_right: int, inorder_left: int, inorder_right: int):
if preorder_left > preorder_right:
return None
# 前序遍历中的第一个节点就是根节点
preorder_root = preorder_left
# 在中序遍历中定位根节点
inorder_root = index[preorder[preorder_root]]
# 先把根节点建立出来
root = TreeNode(preorder[preorder_root])
# 得到左子树中的节点数目
size_left_subtree = inorder_root - inorder_left
# 递归地构造左子树,并连接到根节点
# 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = myBuildTree(preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1)
# 递归地构造右子树,并连接到根节点
# 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = myBuildTree(preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right)
return root
n = len(preorder)
# 构造哈希映射,帮助我们快速定位根节点
index = {element: i for i, element in enumerate(inorder)}
return myBuildTree(0, n - 1, 0, n - 1)
二叉树中的最大路径和(124H)
难度:【困难】
思路:递归
本质就是后序遍历,对于一个二叉树节点,计算左子树和右子树的最大路径和,再加上自己的值,得到该节点的最大路径和。
- 首先实现一个简化函数maxGain(node),计算二叉树中一个节点的最大贡献值
- 计算二叉树的最大路径和,对于二叉树中的一个节点,该节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值,如果子节点的最大贡献值为正,则计入该节点的最大路径和,否则不计入该节点的最大路径和
- 维护一个全局变量maxSum存储最大路径和,在递归过程中更新maxSum的值。
代码:
class Solution:
def __init__(self):
self.maxSum = float("-inf")
def maxPathSum(self, root: TreeNode) -> int:
def maxGain(node):
if not node:
return 0
leftGain = max(maxGain(node.left),0)
rightGain = max(maxGain(node.right),0)
priceNewPath = node.val + leftGain + rightGain
self.maxSum = max(self.maxSum, priceNewPath)
return node.val + max(leftGain, rightGain)
maxGain(root)
return self.maxSum
时间复杂度:O(N)
空间复杂度:O(N)
二叉树的前序遍历(144E)
难度:【简单】
方法一:递归
树本身就有递归的特性,因此递归方法最简单,这里直接放上代码,需要说明的是,中序遍历,前序遍历和后序遍历可采用相同的代码模板完成实现。
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
时间复杂度:O(n),n 为树的节点个数
空间复杂度:O(h),h 为树的高度
方法二:迭代
代码如下:
class Solution:
def preorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
stack = []
res = []
cur = root
while stack or cur:
while cur:
stack.append(cur)
res.append(cur.val)
cur = cur.left
cur = stack.pop()
cur = cur.right
return res
时间复杂度:O(n),n 为树的节点个数
空间复杂度:O(h),h 为树的高度
二叉树的后序遍历(145E)
难度:【中等】
方法一:递归
树本身就有递归的特性,因此递归方法最简单,这里直接放上代码,需要说明的是,中序遍历,前序遍历和后序遍历可采用相同的代码模板完成实现。
代码如下:
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val]
时间复杂度:O(n),n 为树的节点个数
空间复杂度:O(h),h 为树的高度
方法二:迭代
注意:该代码是基于前序遍历改来的,由于前序遍历是中左右,后序遍历是左右中,所以只需要写出中右左,再进行反转即可得到左右中。
代码如下;
class Solution:
def postorderTraversal(self, root: TreeNode) -> List[int]:
if not root:
return []
res = []
stack = []
cur = root
while stack or cur:
while cur:
stack.append(cur)
res.append(cur.val)
cur = cur.right
cur = stack.pop()
cur = cur.left
return res[::-1]
时间复杂度:O(n),n 为树的节点个数
空间复杂度:O(h),h 为树的高度
二叉搜索树的最近公共祖先(235E)
难度:【简单】
第一种思路:对于两个节点,从下往上找,依次找到对应的路径,在对两个路径找到相同的结点。(不好实现)
第二种思路:从根节点找到两个结点对应的路径,对两个路径进行查找。
代码如下:
第三种思路:采用递归的方法进行查找。
代码如下:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val < root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
elif p.val > root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
else:
return root
第四种:非递归的写法,while循环来完成。
代码如下:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
while root:
if p.val < root.val > q.val:
root = root.left
elif p.val > root.val < q.val:
root = root.right
else:
return root
二叉树的最近公共祖先(236M)
难度:【中等】
第一种思路:对于两个节点,从下往上找,依次找到对应的路径,在对两个路径找到相同的结点。(不好实现)
第二种思路:从根节点找到两个结点对应的路径,对两个路径进行查找。
第三种思路:采用递归的方法进行查找。
解法:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/236-er-cha-shu-de-zui-jin-gong-gong-zu-xian-hou-xu/
代码如下:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root:
return root
if root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left: return right
if not right: return left
return root