0437. 路径总和 III

题目地址(437. 路径总和 III)

https://leetcode-cn.com/problems/path-sum-iii/

题目描述

1
给定一个二叉树,它的每个结点都存放着一个整数值。
2
3
找出路径和等于给定数值的路径总数。
4
5
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
6
7
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
8
9
示例:
10
11
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
12
13
10
14
/ \
15
5 -3
16
/ \ \
17
3 2 11
18
/ \ \
19
3 -2 1
20
21
返回 3。和等于 8 的路径有:
22
23
1. 5 -> 3
24
2. 5 -> 2 -> 1
25
3. -3 -> 11
Copied!

前置知识

  • hashmap

公司

  • 阿里
  • 腾讯
  • 百度
  • 字节

思路

这道题目是要我们求解出任何一个节点出发到子孙节点的路径中和为指定值。 注意这里,不一定是从根节点出发,也不一定在叶子节点结束。
一种简单的思路就是直接递归解决,空间复杂度 O(n) 时间复杂度介于 O(nlogn) 和 O(n^2), 具体代码:
1
/**
2
* Definition for a binary tree node.
3
* function TreeNode(val) {
4
* this.val = val;
5
* this.left = this.right = null;
6
* }
7
*/
8
// the number of the paths starting from self
9
function helper(root, sum) {
10
if (root === null) return 0;
11
const l = helper(root.left, sum - root.val);
12
const r = helper(root.right, sum - root.val);
13
14
return l + r + (root.val === sum ? 1 : 0);
15
}
16
/**
17
* @param {TreeNode} root
18
* @param {number} sum
19
* @return {number}
20
*/
21
var pathSum = function (root, sum) {
22
// 空间复杂度O(n) 时间复杂度介于O(nlogn) 和 O(n^2)
23
// tag: dfs tree
24
if (root === null) return 0;
25
// the number of the paths starting from self
26
const self = helper(root, sum);
27
// we don't know the answer, so we just pass it down
28
const l = pathSum(root.left, sum);
29
// we don't know the answer, so we just pass it down
30
const r = pathSum(root.right, sum);
31
32
return self + l + r;
33
};
Copied!
但是还有一种空间复杂度更加优秀的算法,利用 hashmap 来避免重复计算,时间复杂度和空间复杂度都是 O(n)。 这种思路是subarray-sum-equals-k的升级版本,如果那道题目你可以 O(n)解决,这道题目难度就不会很大, 只是将数组换成了二叉树。关于具体的思路可以看这道题目
这里有一个不一样的地方,这里我说明一下,就是为什么要有hashmap[acc] = hashmap[acc] - 1;, 原因很简单,就是我们 DFS 的时候,从底部往上回溯的时候,map 的值应该也回溯。如果你对回溯法比较熟悉的话, 应该很容易理解,如果不熟悉可以参考这道题目, 这道题目就是通过tempList.pop()来完成的。
另外我画了一个图,相信看完你就明白了。
当我们执行到底部的时候:
437.path-sum-iii
接着往上回溯:
437.path-sum-iii-2
很容易看出,我们的 hashmap 不应该有第一张图的那个记录了,因此需要减去。
具体实现见下方代码区。

关键点解析

  • 通过 hashmap,以空间换时间
  • 对于这种连续的元素求和问题,有一个共同的思路,可以参考这道题目

代码

  • 语言支持:JS, Python
JS code:
1
/*
2
* @lc app=leetcode id=437 lang=javascript
3
*
4
* [437] Path Sum III
5
*/
6
/**
7
* Definition for a binary tree node.
8
* function TreeNode(val) {
9
* this.val = val;
10
* this.left = this.right = null;
11
* }
12
*/
13
function helper(root, acc, target, hashmap) {
14
// see also : https://leetcode.com/problems/subarray-sum-equals-k/
15
16
if (root === null) return 0;
17
let count = 0;
18
acc += root.val;
19
if (acc === target) count++;
20
if (hashmap[acc - target] !== void 0) {
21
count += hashmap[acc - target];
22
}
23
if (hashmap[acc] === void 0) {
24
hashmap[acc] = 1;
25
} else {
26
hashmap[acc] += 1;
27
}
28
const res =
29
count +
30
helper(root.left, acc, target, hashmap) +
31
helper(root.right, acc, target, hashmap);
32
33
// 这里要注意别忘记了
34
hashmap[acc] = hashmap[acc] - 1;
35
36
return res;
37
}
38
39
var pathSum = function (root, sum) {
40
const hashmap = {};
41
return helper(root, 0, sum, hashmap);
42
};
Copied!
Python Code:
1
import collections
2
'''
3
class TreeNode:
4
def __init__(self, val=0, left=None, right=None):
5
self.val = val
6
self.left = left
7
self.right = right
8
'''
9
class Solution:
10
def helper(self,root,acc,target,hashmap):
11
if not root:
12
return 0
13
count=0
14
acc+=root.val
15
if acc==target:
16
count+=1
17
if acc-target in hashmap:
18
count+=hashmap[acc-target]
19
hashmap[acc]+=1
20
if root.left:
21
count+=self.helper(root.left,acc,target,hashmap)
22
if root.right:
23
count+=self.helper(root.right,acc,target,hashmap)
24
hashmap[acc]-=1
25
return count
26
27
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
28
hashmap=collections.defaultdict(lambda:0)
29
return self.helper(root,0,targetSum,hashmap)
Copied!
复杂度分析
  • 时间复杂度:$O(N)$
  • 空间复杂度:$O(N)$
更多题解可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。