揭秘破解LeetCode神技:掌握160、404、437,二叉树也能畅行无阻
2023-10-26 03:47:45
二叉树概述
二叉树是一种重要的数据结构,它由节点组成,每个节点至多有两棵子树,分别称为左子树和右子树。二叉树广泛应用于计算机科学的各个领域,例如查找、排序、存储和压缩等。
LeetCode题160:二叉树中和为给定值路径数目
题目
给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
算法思路:
-
递归法:该算法采用自顶向下的方式,递归地计算每个节点到所有子节点的路径和。当路径和等于给定值时,计数器加一。时间复杂度为O(n^2),其中n为树的节点数。
-
动态规划法:该算法采用自底向上的方式,先计算每个节点到其子节点的路径和,然后逐步计算每个节点到其祖先节点的路径和。时间复杂度为O(n),空间复杂度为O(n)。
代码实现:
# 递归法
def path_sum(root, target_sum):
if not root:
return 0
# 计算以当前节点为起点的路径和
current_sum = root.val
# 统计以当前节点为起点的路径和为target_sum的路径数
path_count = 0
if current_sum == target_sum:
path_count += 1
# 递归计算左右子树的路径和
path_count += path_sum(root.left, target_sum - current_sum)
path_count += path_sum(root.right, target_sum - current_sum)
return path_count
# 动态规划法
def path_sum_dp(root, target_sum):
# 创建一个字典,key为路径和,value为路径数
path_sums = {0: 1}
# 递归计算每个节点到其子节点的路径和
def dfs(root, current_sum):
if not root:
return 0
# 计算以当前节点为起点的路径和
current_sum += root.val
# 统计以当前节点为起点的路径和为target_sum的路径数
path_count = path_sums.get(current_sum - target_sum, 0)
# 更新字典中的路径和
path_sums[current_sum] = path_sums.get(current_sum, 0) + 1
# 递归计算左右子树的路径和
path_count += dfs(root.left, current_sum)
path_count += dfs(root.right, current_sum)
# 撤销当前节点的路径和更新
path_sums[current_sum] -= 1
return path_count
return dfs(root, 0)
LeetCode题404:左叶子之和
题目:
给定一个二叉树,计算所有左叶子之和。左叶子是指左子树没有子节点的叶子节点。二叉树不超过2000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
算法思路:
-
递归法:该算法采用自顶向下的方式,递归地遍历二叉树。当遇到左叶子节点时,将该节点的值添加到结果中。时间复杂度为O(n),其中n为树的节点数。
-
深度优先搜索(DFS):该算法采用深度优先的方式,遍历二叉树。当遇到左叶子节点时,将该节点的值添加到结果中。时间复杂度为O(n),其中n为树的节点数。
-
广度优先搜索(BFS):该算法采用广度优先的方式,遍历二叉树。当遇到左叶子节点时,将该节点的值添加到结果中。时间复杂度为O(n),其中n为树的节点数。
代码实现:
# 递归法
def sum_of_left_leaves(root):
if not root:
return 0
# 计算左子树的左叶子之和
left_sum = sum_of_left_leaves(root.left)
# 计算右子树的左叶子之和
right_sum = sum_of_left_leaves(root.right)
# 如果当前节点是左叶子,则将当前节点的值添加到结果中
if not root.left and not root.right:
return root.val
return left_sum + right_sum
# 深度优先搜索(DFS)
def sum_of_left_leaves_dfs(root):
stack = [root]
total_sum = 0
while stack:
# 弹出栈顶元素
node = stack.pop()
# 如果当前节点是左叶子,则将当前节点的值添加到结果中
if node.left and not node.left.left and not node.left.right:
total_sum += node.left.val
# 将右子树压入栈中
if node.right:
stack.append(node.right)
# 将左子树压入栈中
if node.left:
stack.append(node.left)
return total_sum
# 广度优先搜索(BFS)
def sum_of_left_leaves_bfs(root):
queue = [root]
total_sum = 0
while queue:
# 弹出队列首元素
node = queue.pop(0)
# 如果当前节点是左叶子,则将当前节点的值添加到结果中
if node.left and not node.left.left and not node.left.right:
total_sum += node.left.val
# 将右子树入队
if node.right:
queue.append(node.right)
# 将左子树入队
if node.left:
queue.append(node.left)
return total_sum
LeetCode题437:路径总和III
题目:
给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
算法思路:
-
递归法:该算法采用自顶向下的方式,递归地计算每个节点到所有子节点的路径和。当路径和等于给定值时,计数器加一。时间复杂度为O(n^2),其中n为树的节点数。
-
动态规划法:该算法采用自底向上的方式,先计算每个节点到其子节点的路径和,然后逐步计算每个节点到其祖先节点的路径和。时间复杂度为O(n),空间复杂度为O(n)。
代码实现:
# 递归法
def path_sum(root, target_sum):
if not root:
return 0
# 计算以当前节点为起点的路径和
current_sum = root.val
# 统计以当前节点为起点的路径和为target_sum的路径数
path_count = 0
if current_sum == target_sum:
path_count += 1
# 递归计算左右子树的路径和
path_count += path_sum(root.left, target_sum - current_sum)
path_count += path_sum(root.right, target_sum - current_sum)
return path_count
# 动态规划法
def path_sum_dp(root, target_sum):
# 创建一个字典,key为路径和,value为路径数