LeetCode题目112:多种算法实现路径总与改进过程

简介: LeetCode题目112:多种算法实现路径总与改进过程

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

python源码解读

程序员必备的数学知识与应用

题目描述

给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

示例

示例

输入:

5
   / \
  4   8
 /   / \
11  13  4
/ \      \
7   2      1

目标和 = 22

输出:True(存在路径 5 -> 4 -> 11 -> 2,和为 22)

方法一:递归深度优先搜索(DFS)

解题步骤
  1. 递归函数定义:定义一个辅助函数来递归检查每个节点,传递当前的累计总和。
  2. 递归终止条件:如果当前节点是叶子节点,并且其值加上累计总和等于目标值,返回 True
  3. 递归逻辑:递归检查当前节点的左右子节点。
Python 示例
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
def hasPathSum(root, sum):
    """
    检查二叉树中是否存在根到叶子的路径总和等于给定值
    :param root: TreeNode, 二叉树的根节点
    :param sum: int, 目标和
    :return: bool
    """
    if not root:
        return False
    sum -= root.val
    if not root.left and not root.right:  # 检查是否为叶子节点
        return sum == 0
    return hasPathSum(root.left, sum) or hasPathSum(root.right, sum)
算法分析
  • 时间复杂度:(O(n)),每个节点访问一次。
  • 空间复杂度:(O(h)),递归栈的深度,其中 (h) 是树的高度。

方法一使用递归深度优先搜索(DFS)来寻找是否存在从根到叶子的路径,其和等于给定的目标值。虽然这种方法直观且易于实现,但在某些情况下可能会进行不必要的递归调用,尤其是在不平衡的树中。因此,我们可以通过一些技术改进它,以提高效率和实用性。

方法一改进:优化的递归DFS

改进点
  1. 短路逻辑:在递归过程中,一旦找到符合条件的路径,即可立即停止进一步的递归,避免不必要的计算。
  2. 减少参数传递:可以通过直接修改传递的 sum 参数来减少参数的数量,这样可以稍微降低递归调用的开销。
改进后的 Python 示例
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
def hasPathSum(root, sum):
    """
    使用优化的DFS检查是否存在从根到叶的路径总和等于给定值
    :param root: TreeNode, 二叉树的根节点
    :param sum: int, 目标和
    :return: bool
    """
    if not root:
        return False
    # 检查是否到达叶子节点并且路径总和匹配
    if not root.left and not root.right:
        return root.val == sum
    # 递归检查左右子树
    sum -= root.val
    return hasPathSum(root.left, sum) or hasPathSum(root.right, sum)
# 示例调用
root = TreeNode(5, TreeNode(4, TreeNode(11, TreeNode(7), TreeNode(2)), None), TreeNode(8, TreeNode(13), TreeNode(4, None, TreeNode(1))))
print(hasPathSum(root, 22))  # 输出: True
算法分析
  • 时间复杂度:改进后,时间复杂度依然为 (O(n)),因为每个节点仍然需要至多被访问一次。
  • 空间复杂度:改进后,空间复杂度也为 (O(h)),其中 (h) 是树的高度,对应于递归栈的最大深度。通过短路逻辑,可能在找到第一个有效路径时减少空间使用。
优劣势比较
  • 优点
  • 短路逻辑可以减少在找到有效路径后的不必要递归,提高效率。
  • 直接修改 sum 减少了参数传递,稍微优化了递归的性能。
  • 缺点
  • 递归深度依然依赖于树的高度,对于极端不平衡的树依然可能导致较高的空间复杂度。

这种改进使得递归方法在实际应用中更加高效,尤其是在早期找到符合条件的路径时,能够显著减少计算量。

方法二:迭代使用栈

解题步骤
  1. 使用栈:利用栈存储每个节点及其对应的路径总和。
  2. 迭代逻辑:迭代访问每个节点,更新路径总和,检查叶子节点的路径总和。
Python 示例
def hasPathSum(root, sum):
    if not root:
        return False
    stack = [(root, root.val)]
    while stack:
        node, curr_sum = stack.pop()
        if not node.left and not node.right and curr_sum == sum:
            return True
        if node.right:
            stack.append((node.right, curr_sum + node.right.val))
        if node.left:
            stack.append((node.left, curr_sum + node.left.val))
    return False
算法分析
  • 时间复杂度:(O(n)),每个节点最多被访问一次。
  • 空间复杂度:(O(n)),在最坏的情况下,栈中需要存储所有节点。

方法二使用迭代的方式通过栈实现深度优先搜索(DFS),检查是否存在从根到叶的路径,其和等于给定目标值。虽然迭代方法减少了递归可能引起的栈溢出问题,但其管理栈的方式仍有改进空间,特别是在如何更高效地处理节点和路径和的记录。

方法二改进:优化的迭代DFS

改进点
  1. 使用结构体或类:为了减少重复的元素推入和弹出操作,可以创建一个简单的类或结构体来存储节点以及到该节点为止的累积和,这样可以使代码更加清晰且减少错误。
  2. 早停机制:在发现第一个符合条件的叶子节点时立即停止所有操作,避免不必要的迭代。
改进后的 Python 示例
from collections import deque
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right
class PathNode:
    def __init__(self, node, current_sum):
        self.node = node
        self.current_sum = current_sum
def hasPathSum(root, targetSum):
    if not root:
        return False
    stack = deque([PathNode(root, root.val)])  # 使用PathNode来存储节点和当前路径和
    while stack:
        path_node = stack.pop()
        node = path_node.node
        current_sum = path_node.current_sum
        # 检查是否到达叶子节点且路径和符合条件
        if not node.left and not node.right and current_sum == targetSum:
            return True
        # 将非空子节点和相应的路径和压入栈
        if node.right:
            stack.append(PathNode(node.right, current_sum + node.right.val))
        if node.left:
            stack.append(PathNode(node.left, current_sum + node.left.val))
    return False
# 示例调用
root = TreeNode(5, TreeNode(4, TreeNode(11, TreeNode(7), TreeNode(2)), None), TreeNode(8, TreeNode(13), TreeNode(4, None, TreeNode(1))))
print(hasPathSum(root, 22))  # 输出: True
算法分析
  • 时间复杂度:优化后,时间复杂度仍为 (O(n)),每个节点最多被访问一次。
  • 空间复杂度:优化后,空间复杂度也为 (O(n)),在最坏的情况下可能需要存储所有节点。
优劣势比较
  • 优点
  • 代码结构更清晰,通过使用 PathNode 类减少了代码的复杂度和出错概率。
  • 早停机制提高了效率,避免了不必要的迭代。
  • 缺点
  • 空间复杂度相比递归方法有所提高,因为迭代方法需要显式使用栈存储节点。

通过这种改进,迭代方法在处理大型数据集时更加健壮且易于维护,尤其适用于深度较大的树结构,减少了递归可能导致的栈溢出风险。

应用示例

这些方法在计算机科学中广泛应用于路径查找、网络流量分析、资源管理等领域,其中需要确定从一个点到另一个点的可达性或路径成本。


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
1月前
【LeetCode 35】112.路径总和
【LeetCode 35】112.路径总和
24 0
|
1月前
【LeetCode 36】113.路径总和II
【LeetCode 36】113.路径总和II
28 0
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
14天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
27 2
|
1月前
|
数据采集 监控 安全
厂区地图导航制作:GIS技术与路径导航算法融合
在智能化、数字化时代,GIS技术为厂区的运营管理带来了革命性变化。本文探讨了如何利用GIS技术,通过数据采集、地图绘制、路径规划、位置定位和信息查询等功能,打造高效、精准的智能厂区地图导航系统,提升企业的竞争力和管理水平。
50 0
厂区地图导航制作:GIS技术与路径导航算法融合
|
1月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
1月前
【LeetCode 34】257.二叉树的所有路径
【LeetCode 34】257.二叉树的所有路径
17 0
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行