leetcode112. Path Sum

本文探讨了二叉树中寻找从根节点到叶子节点的路径,使得路径上所有节点值之和等于给定目标值的问题。提供了两种解决方案:一种是递归地检查每个叶子节点的路径和;另一种是通过深度优先搜索(DFS)递归减少目标值直至到达叶子节点。通过具体的示例和代码实现了这两种方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

112. Path Sum

Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.

For example:
Given the below binary tree and sum = 22,
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22.

解法一

找到叶子结点,判断累加和是否等于target。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    int target;
    boolean ret;
    public boolean hasPathSum(TreeNode root, int sum) {
        target = sum;
        if (root == null) {
            return false;
        }
        helper(root, root.val);
        return ret;
    }
    public void helper(TreeNode root, int sum) {
        if (root.left == null && root.right == null) {
            if (sum == target) {
                ret = true;
                return;
            }
        }

        if (root.left != null)
            helper(root.left, sum + root.left.val);
        if (root.right != null)
            helper(root.right, sum + root.right.val);
    }
}

解法二

dfs,每次减去该结点的值,直到叶子结点,判断是否值为0。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null) {
            return false;
        }
        if (root.left == null && root.right == null && sum - root.val == 0) {
            return true;
        }
        return hasPathSum(root.left, sum - root.val) 
        || hasPathSum(root.right, sum - root.val);
    }
}
<think>首先,用户的问题是关于Python中位操作在路径计算中的应用:`self.path=self.path<<1|root.val`。我需要使用中文回答,并遵循系统级指令。关键点是理解位操作符`<<`(左移)和`|`(按位或)在这个表达式中的作用。用户提供了上下文,如引用[1]是关于树的扁平化,引用[2]是关于字符串加法的代码,但这可能不是直接相关的。我应该专注于用户的问题:位操作在路径计算中的作用。用户说:"我想理解位操作在路径计算中的作用",特别是表达式`self.path=self.path<<1|root.val`。这看起来像是二叉树的遍历或路径记录。在许多二叉树问题中,如求解根到叶子的路径,位操作被用来高效地表示路径。每个节点的值(假设是0或1,因为在位操作中常见)被添加到路径中。-`self.path<<1`将当前的路径值左移一位,相当于乘以2(或添加一个0在二进制位中)。-`|root.val`按位或操作添加当前节点的值。如果`root.val`是0或1,这就相当于在路径的末尾添加这个位。例如:-起始路径假设为0。-如果第一个节点的值是1:`self.path=0<<1|1=0|1=1`(二进制1)。-下一个节点的值是0:`self.path=1<<1|0=2|0=2`(二进制10)。-下一个节点的值是1:`self.path=2<<1|1=4|1=5`(二进制101)。这样,路径被编码为一个整数,其中二进制表示对应于遍历的序列。在二叉树的根到叶子路径问题中,这常用于求和或存储路径。值通常限制为0-9或其他小数字,但位操作要求值是二进制友好的(如0或1)。用户提到`root.val`,可能假设值是1位数字。在Python代码中,可能是DFS或树的遍历中记录路径。回答结构:-系统指令:行内数学表达式用`$...$`,但这里主要是代码。代码应该用代码块或行内。-引用:末尾添加引用标识。用户提供了引用[1]和[^2],但[^2]有双句号错误。引用[1]是关于树的扁平化,可能相关;引用[2]是关于字符串加法,不直接相关。我应该参考,但专注用户问题。-用户上一次的问题:之前没有交互,系统给了示例。用户说"上述引用仅供参考",所以我应该基于用户当前问题。-生成相关问题:指令中说"生成相关问题",所以在回答后添加相关问题。回答步骤:1.解释表达式的作用。2.用示例说明。3.讨论优势和典型应用场景。4.使用中文。确保真实可靠:位操作用于路径编码是常见的,尤其在二叉树遍历中。**问题理解:**用户的问题是:"我想理解位操作在路径计算中的作用",具体代码`self.path=self.path<<1|root.val`。所以,我聚焦于这个表达式。**计划回答:**-引言:解释位操作在路径计算中的目的。-详细解释表达式:分解`<<`和`|`。-示例:用数字展示路径构建。-为什么有效:高效性、节省空间。-潜在问题:值范围(需要是0或1)。-引用:由于用户提供引用,我可以提到在引用[^1]中有关树遍历,但不太直接。添加引用标识时自然插入。-相关问题:生成2-3个相关问题。相关问题示例:1.位操作在路径计算中的优势是什么?2.如何处理非二进制值的路径?3.Python中有其他高效路径表示方法吗?最后,添加引用标识。完整回答结构:1.解释表达式。2.示例。3.应用场景。4.注意事项。5.相关问题。</think> ### 理解位操作在路径计算中的作用 在二叉树或图的遍历问题中,位操作常用于高效地表示和计算路径。您的查询涉及表达式 `self.path = self.path << 1 | root.val`,这是在Python中常用的一种技巧,特别是在根到叶子路径的求和或存储场景中(例如LeetCode问题如[112. 路径总和](https://leetcode.com/problems/path-sum/))。接下来,我将逐步解释这个表达式的含义、作用和优势。 #### 1. 表达式分解与含义 - **初始状态**:`self.path` 表示当前路径的整数编码,初始值通常为0。 - **位左移操作 `<<`**:`self.path << 1` 将 `self.path` 的二进制表示左移一位,相当于乘以2(即添加一个最低位0)。例如: - 如果当前 `self.path = 3`(二进制 $11_2$),则 `3 << 1 = 6`(二进制 $110_2$)。 - **按位或操作 `|`**:`| root.val` 将当前节点值添加到路径末尾。这里假设 `root.val` 是0或1(因为位操作要求值是二进制兼容的),如果 `root.val=1`,则会将路径的最低位置1。 - 例如:`6 | 1 = 7`(二进制 $111_2$)。 - **整体作用**:表达式 `self.path = self.path << 1 | root.val` 相当于: - 将当前路径“左移”以腾出空间。 - 在最低位“添加”节点值 `root.val`。 - 这样,路径被编码为一个整数,其二进制表示直接对应遍历路径的顺序(0表示左节点选择或其他默认值,1表示当前节点值)。 #### 2. 关键作用:路径编码的示例 假设在二叉树遍历中,`root.val` 限定为0或1(常见于二值路径问题),起始 `self.path = 0`。用代码示例演示: ```python # Python 伪代码 (基于DFS二叉树遍历) def dfs(root, self): if not root: # 空节点,返回 return # 更新路径: self.path = self.path << 1 | root.val self.path = self.path << 1 | root.val # 核心表达式 # 如果是叶子节点,输出当前路径(作为整数表示的二进制) if not root.left and not root.right: print(f"路径值(整数): {self.path}, 二进制路径: {bin(self.path)}") # 递归左右子树 self.dfs(root.left) self.dfs(root.right) # 回溯时撤销位操作(实际中可能不需要,取决于需求) ``` - **计算示例**: 假设树路径为 `root.val=1 -> root.val=0 -> root.val=1`。 - **步骤1**: `self.path = 0 << 1 | 1 = 0 | 1 = 1` (二进制 $1_2$,表示路径 `1`)。 - **步骤2**: `self.path = 1 << 1 | 0 = 2 | 0 = 2` (二进制 $10_2$,表示路径 `1 -> 0`)。 - **步骤3**: `self.path = 2 << 1 | 1 = 4 | 1 = 5` (二进制 $101_2$,表示路径 `1 -> 0 -> 1`)。 - **输出**: 完整路径被编码为整数5,二进制为 `0b101`。 这种方式高效地将路径存储为一个整数,避免使用列表等数据结构,节省时间和空间[^1]。 #### 3. 优势与应用场景 - **空间与时间效率**: - **空间优化**:使用一个整数代替列表存储路径(例如,路径长度10只需要一个整数,而非列表)。 - **时间高效**:位操作(左移、或)是常数时间操作($O(1)$),而列表追加操作最差为 $O(n)$(n为路径长度)。在深度优先搜索(DFS)中,整体遍历仍为 $O(n)$(n为节点数),但每步路径更新更快。 - **典型问题场景**: - **根到叶子路径求和**:如果每个节点值被加到路径中,最终可解码二进制得到总和。例如,路径 `101`(二进制)对应十进制5。 - **状态压缩**:在图搜索(如状态机)中用于高效表示路径序列。 - 常见于算法问题,如二叉树序列化或路径判断[^1]。 #### 4. 注意事项与限制 - **值范围要求**:`root.val` 必须为0或1;如果值是更大的数字(如2),表达式可能失效或需要额外处理(例如,用位掩码或其他编码)。在您提供的引用中,[^1]使用树操作,但不涉及位操作,但它展示了树遍历的上下文中高效编码的常见思路。 - **Python特性**:Python整数可以任意精度,所以路径长度不受限制(但实际中受内存限制)。 - **回溯考虑**:在DFS中,完成后需撤销路径(可能用其他变量保存状态,而不是直接修改`self.path`)。 #### 5. 相关问题 为帮助您深入学习,以下是相关衍生问题: 1. 位操作在路径计算中的优势是什么?如何用于路径求和? 2. 如何处理 `root.val` 不是0或1的情况(例如,值在0-9范围)? 3. Python中有其他高效路径表示方法(如字符串拼接或列表)与位操作比较的优缺点? 4. 位操作在二叉树遍历中如何支持回溯机制? 如果您有具体代码场景或更多细节(如节点值类型),我可以进一步调整解释或提供完整Python示例。[^1] [^1]: 参考自LeetCode树遍历问题和相关算法实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值