题目:求和路径
给定一棵二叉树,其中每个节点都含有一个整数数量(该值或正或负)。设计一个算法,打印节点数值总和等于某个给定值的所有路径(求路径数量!)。注意,路径不一定非得从二叉树得根节点或叶节点开始或结束,但是某方向必须向下(只能从父节点指向子节点方向)。
一、思路
1.先用蛮力法解决,只需要查看所有可能得路径。遍历每个节点,用递归法尝试所有向下的路径。并随着递归的进行跟踪路径的和。每当发现路径和等于目标和,答案就+1;用时O(NlogN) 每个点遍历完需要LogN。
2.尝试在蛮力法上优化,蛮力法有很多重复计算。对于像10→5→3→-2这样的路径,遍历10为起点时 5,3,-2会被遍历,遍历5为起点时 3,-2会被遍历,所有3,-2会被重复遍历,理想情况下,我们希望能够对该过程进行重用。
假设,对于数组(10,5,1,2,-1,-1,7,1,2)中,有多少连续的子序列相加等于目标和,比如8.
我们可以转换问题求解,对于每个元素y,我们试图找到符合下面描述的x的值?

如果数组中的每个元素都知道路径的行程和,那么求解问题就容易很多,只需要使用如下的等式,即
r
u
n
n
i
n
g
S
u
m
x
=
r
u
n
n
i
n
g
S
u
m
y
−
t
a
r
g
e
t
S
u
m
runningSum_x =runningSum_y - targetSum
runningSumx=runningSumy−targetSum 。之后,我们只需要找出满足此公式的x的值即可。

建立一个键为
r
u
n
n
i
n
g
S
u
m
runningSum
runningSum,其值为
r
u
n
n
i
n
g
S
u
m
runningSum
runningSum出现的次数。之后,对于每一个元素y,我们散列表中以
r
u
n
n
i
n
g
S
u
m
y
−
t
a
r
g
e
r
S
u
m
runningSum_y-targerSum
runningSumy−targerSum为键进行查找。散列表返回的值则表示为终止于元素y,且路径总和为
t
a
r
g
e
t
S
u
m
targetSum
targetSum的路径数量。
例如:

r
u
n
n
i
n
g
S
u
m
7
runningSum_7
runningSum7的值为24.如果
t
a
r
g
e
t
S
u
m
targetSum
targetSum的值是8,那么我们需要在散列表中查找键16,该键返回的值为2(有2个键为16的值,即数组索引为2开始和索引5开始的路径)。如上所示,索引3至索引7 和 索引3至索引7两条路径的和为8。
算法描述:
使用深度优化查找对树进行遍历。当我们访问每个节点时,执行一下操作
- 跟踪 r u n n i n g S u m runningSum runningSum的值。我们将使该变量成为函数的一个参数,并对其增加 node.value。
- 在散列表中查找 r u n n i n g S u m − t a r g e t S u m runningSum - targetSum runningSum−targetSum。我们从散列表获得的值为路径的总数。将变量 totalPaths 的值设置为该值
- 如果 r u n n i n g S u m = = t a r g e t S u m runningSum == targetSum runningSum==targetSum,则发现了另外一条从根节点开始的路径。将变量 totalPaths加 1
- 将 r u n n i n g S u m runningSum runningSum加入到散列表中(如果 r u n n i n g S u m runningSum runningSum已经存在,则将增加其值)
- 对左子树和右子树进行递归,计算和为 targetSum 的路径的条数
- 对左子树和右子树的递归调用结束后,减少散列表 r u n n i n g S u m runningSum runningSum 对应的值。这是算法中进行回溯的过程,它恢复了前述步骤对散列表的修改,以便其他节点不受影响(这是因为我们已经完成了对当前节点的处理)
二、解法
1.蛮力法
int pathSum(TreeNode* root, int sum) {
if(root == NULL)return 0;
int pathRoot = countPathsWithSumFromNode(root, 0, sum);
int pathLeft = pathSum(root->left, sum);
int pathright = pathSum(root->right, sum);
return pathRoot + pathLeft + pathright;
}
int countPathsWithSumFromNode(TreeNode *node, int curSum, int targetNum){
if(node == NULL) return 0;
curSum += node->val;
int totalPaths = 0;
if(curSum == targetNum){
return totalPaths++;
}
totalPaths += countPathsWithSumFromNode(node->left, curSum, targetNum);
totalPaths += countPathsWithSumFromNode(node->right, curSum, targetNum);
return totalPaths;
}
2.优化解法1
int pathSum(TreeNode* root, int sum) {
unordered_map<int, int> pathCount;
return countPathWithSum(root, sum, 0, pathCount);
}
int countPathWithSum(TreeNode *node, int targetSum, int runningSum, unordered_map<int, int> &pathCount){
if(node == NULL) return 0;
runningSum += node->val;
int sum = runningSum - targetSum;
int totalPaths = 0;
if(pathCount.count(sum)){
totalPaths = pathCount[sum];
}
if(runningSum == targetSum){//发现从根节点到此点的路径和为目标值
totalPaths++;
}
incrementHashTable(pathCount, runningSum, 1);
totalPaths += countPathWithSum(node->left, targetSum, runningSum, pathCount);
totalPaths += countPathWithSum(node->right, targetSum, runningSum, pathCount);
incrementHashTable(pathCount, runningSum, -1);
return totalPaths;
}
void incrementHashTable(unordered_map<int, int> &pathCount, int key, int delta){
if(pathCount.count(key)){
int newCount = pathCount[key] + delta;
if(newCount == 0){
pathCount.erase(key);
}else{
pathCount[key] = newCount;
}
return;
}
pathCount[key] = delta;
}
这篇博客介绍了如何在二叉树中寻找节点值之和等于给定值的路径,主要讨论了两种方法:蛮力法和优化解法。优化解法利用了散列表来避免重复计算,提高了效率。

788

被折叠的 条评论
为什么被折叠?



