leetcode
leetcode 2951 ~ 3000
路径总和 III

路径总和 III

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 34 ms, 内存: 16.5 MB


/* 
思路:
1. 将树的节点转换为列表。
2. 使用流操作计算路径和。
3. 通过递归计算每个节点的路径和。
4. 使用流操作求和。 
*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    public int pathSum(TreeNode root, int targetSum) {
        List<TreeNode> nodes = new ArrayList<>();
        traverse(root, nodes);
        return nodes.stream().mapToInt(node -> countPaths(node, targetSum)).sum();
    }

    private void traverse(TreeNode node, List<TreeNode> nodes) {
        if (node != null) {
            nodes.add(node);
            traverse(node.left, nodes);
            traverse(node.right, nodes);
        }
    }

    private int countPaths(TreeNode node, int sum) {
        if (node == null) return 0;
        return (node.val == sum ? 1 : 0) 
            + countPaths(node.left, sum - node.val) 
            + countPaths(node.right, sum - node.val);
    }
}

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

解释

方法:

该题解采用了深度优先搜索(DFS)和哈希表来解决问题。首先,我们递归地遍历树的每一个节点,同时维护当前路径的累计和。哈希表`Sumpath`用于存储每个节点到根节点路径上的累计和及其出现的次数。对于每个节点,我们检查`当前累计和 - 目标和`是否已经在哈希表中,如果存在,则说明我们找到了一个有效路径。在递归进入左右子节点之前,更新哈希表以包含当前累计和。在从子节点返回后,为了不影响其他路径,需要将当前累计和的计数减一,以防止它干扰其他路径的计算。这种方法有效地利用了前缀和的概念,即使用累计和减去目标值来快速检查是否存在符合条件的路径。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在递归遍历过程中更新哈希表`Sumpath`的操作对算法性能有何影响,尤其是在面对大数据量时?
在递归遍历过程中,每到达一个新的节点,我们都会更新哈希表`Sumpath`以记录当前路径的累计和及其出现次数。这种更新操作包括插入新的键值对和更新已有键的值,通常这些操作的时间复杂度是O(1)。然而,由于这些操作需要在每个节点处执行,因此整体上会对算法的性能产生影响,尤其是当树的大小非常大时。每次更新哈希表都涉及到内存的读写,这在数据量大时可能会成为性能瓶颈。此外,频繁的更新操作可能会影响哈希表的负载因子,进而影响整体性能。总的来说,虽然每次操作的时间复杂度较低,但频繁操作仍可能导致较高的累计时间消耗,尤其是在树的结构复杂或节点数目极多时。
🦆
为什么在从子节点返回到父节点后需要对哈希表`Sumpath`中的当前累计和的计数进行减一操作?
这个操作是回溯的一部分,是必要的以确保每个节点退出递归后不会影响其他路径的计算。在深度优先搜索中,当探索一个节点的所有子节点后,我们需要从总路径和中移除当前节点的值,以反映回到了之前的状态。如果我们不减少哈希表中当前累计和的计数,那么当开始探索其他兄弟节点或父节点的其他路径时,这个累计和仍会错误地反映在哈希表中,这可能导致错误地计算出额外的路径匹配。因此,减一操作是为了保持算法的正确性和防止对未来路径探索的干扰。
🦆
在哈希表`Sumpath`中,初始设置`0:1`的原因是什么?
初始设置`0:1`是为了处理从根节点到当前节点路径累计和正好等于目标和的情况。这种设置相当于提供了一个虚拟的前缀和,表示在任何实际节点之前,有一个和为0的路径。例如,如果从根节点到某个节点的路径和恰好等于目标和,那么根据哈希表中的记录,当前累计和减目标和等于0,查看哈希表我们会发现0已经被记录了1次,这意味着存在一条路径(从根到当前节点)其和为目标和。因此,这种初始化方式是为了方便处理包含根节点的那些路径,其和恰好等于目标和的情况。

相关问题