Leetcode 437:路径总和 III(最详细的解法!!!)

给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

返回 3。和等于 8 的路径有:

1.  5 -> 3
2.  5 -> 2 -> 1
3.  -3 -> 11

解题思路

这个问题非常有意思。和之前问题

Leetcode 112:路径总和(最详细的解法!!!)

Leetcode 113:路径总和 II(最详细的解法!!!)

的区别在于,这个问题不一定是从根节点出发。知道这一点的话,我们很容易写出

def pathSum(self, root, sum):
    """
        :type root: TreeNode
        :type sum: int
        :rtype: int
        """
    result = 0
    if not root:
        return result

    result += self.findPath(root, sum)
    result += self.pathSum(root.left, sum)
    result += self.pathSum(root.right, sum)
    return result

这里我们一定要明确findPathpathSum的区别。findPath的含义就是查找包含root并且和为sum的路径个数。而pathSum是查找不一定包含root并且和为sum的路径个数。也就是含义上pathSum包括了findPath。那么我们能不能使用pathSum替代findPath呢?显然不行。而findPath,我们在前面就写过很多次,不再赘述。

class Solution:
    def findPath(self, root, sum):
        result = 0
        if not root:
            return result

        if root.val == sum:
            result += 1

        result += self.findPath(root.left, sum - root.val)
        result += self.findPath(root.right, sum - root.val)
        return result
        
    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: int
        """
        result = 0
        if not root:
            return result

        result += self.findPath(root, sum)
        result += self.pathSum(root.left, sum)
        result += self.pathSum(root.right, sum)

        return result

你可能已经发现了,上面的解法是一种暴力破解,这种做法中存在着大量的重复运算。我们对这个问题进行优化,其中我们主要用到这样的一个性质:curSum - sum = oldSumoldSum就是我们要记录的。

用题目的例子来说

      10
     /  \
    5   -3
   / \    \
->3   2   11
 / \   \
3  -2   1

当我们遍历到3,我们此时目标是sum=8,我们这个时候不一定要向下找,可以向上找sum=8的路径。我们此时知道从root3这个节点的sum=18,那么这个时候我们只要知道从根节点开始到3这个节点的路径上有没有sum=10的路径就可以了。而sum=10的这个路径,我们可以在向下遍历的过程中,通过一个map记录。这里我们默认情况下,和的个数为0,所以我们要用到collections.defaultdict

import collections
class Solution:
    def pathSum(self, root, sum):
        """
        :type root: TreeNode
        :type sum: int
        :rtype: int
        """
        if not root: 
            return 0

        self.result = 0
        freq = collections.defaultdict(int)
        freq[0] = 1
        self.dfs(root, 0, freq, sum)
        return self.result
        
    def dfs(self, node, pathSum, freq, sum):
        if node:
            pathSum += node.val
            self.result += freq[pathSum - sum]
            freq[pathSum] += 1
            
            self.dfs(node.left, pathSum, freq, sum)
            self.dfs(node.right, pathSum, freq, sum)

            freq[pathSum] -= 1

我们的这些优化居然打出了暴击,从原先的1464ms变成了56ms,超越了100%的用户。

我将该问题的其他语言版本添加到了我的GitHub Leetcode

如有问题,希望大家指出!!!

你可能感兴趣的:(Problems,leetcode解题指南)