二叉树的路径问题
Posted 宇哥在学习
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树的路径问题相关的知识,希望对你有一定的参考价值。
今天刷了几道关于二叉树的路径问题,总结了一些套路。
// 树的数据结构基于以下
// 代码使用 javascript 实现
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
}
257. 二叉树的所有路径
题目链接:https://leetcode-cn.com/problems/binary-tree-paths/
题意:给定一个二叉树,返回所有从根节点到叶子节点的路径。说明: 叶子节点是指没有子节点的节点。
1
/ \
2 3
\
5
输出: ["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
利用辅助函数实现路径拼接的逻辑,再递归调用左右节点,代码如下:
var binaryTreePaths = function(root) {
const res = [];
if (root === null) return res;
help(root, res, '');
return res;
};
var help = function(root, res, cur) {
if (root === null) return;
cur += root.val
if (root.left === null && root.right === null) {
res.push(cur)
} else {
help(root.left, res, `${cur}->`);
help(root.right, res, `${cur}->`);
}
}
404. 左叶子之和
题目链接:https://leetcode-cn.com/problems/sum-of-left-leaves/
题意:计算给定二叉树的所有左叶子之和。
3
/ \
9 20
/ \
15 7
输出:24
解释:在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24
解题思路同样是利用递归,但这次不需要借助辅助函数,只有满足左节点不为空且当前左节点的子节点全部为空时,开始累加。并从根节点开始左右递归累加。
var sumOfLeftLeaves = function(root) {
if (root === null) return 0;
let num = 0;
if (root.left !== null && (root.left.left === null && root.left.right === null)) {
num += root.left.val;
}
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + num;
};
113. 路径总和 ||
题目链接:https://leetcode-cn.com/problems/path-sum-ii/
题意:给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。说明: 叶子节点是指没有子节点的节点。
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
给定如下二叉树,以及目标和 sum = 22
输出:[
[5,4,11,2],
[5,8,4,5]
]
这道题的思路跟 257 很相似,也是需要借助辅助函数和递归来处理,需要注意的是 cur 这个变量往下传递时,应该传递它的副本,否则会造成引用问题。
var pathSum = function(root, sum) {
const res = [];
if (root === null) return res;
help(root, res, [], sum);
return res;
};
var help = function(root, res, cur, target) {
if (root === null) return;
cur.push(root.val);
target -= root.val;
if (root.left === null && root.right === null && target === 0) {
res.push(cur);
return;
} else {
help(root.left, res, cur.slice(), target);
help(root.right, res, cur.slice(), target);
}
}
437. 路径总和 |||
题目链接:https://leetcode-cn.com/problems/path-sum-iii/
题意:给定一个二叉树,它的每个结点都存放着一个整数值。找出路径和等于给定数值的路径总数。路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
说明:二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
[10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 =
10
\
5 -3
\ \
3 2 11
\ \
3 -2 1
3。和等于 8 的路径有:
5 -> 3
5 -> 2 -> 1
3. -3 -> 11
第一种结题的思路与前面几道相似,但不同点在于这次的路径不用从根节点开始,只要满足条件可在任意接节点结束,所以需要用到两层递归,主函数的初次调用除了递归调用左右子节点,还需要借助辅助函数完成另一层递归。代码如下:
var pathSum = function(root, sum) {
if (root === null) return 0;
return pathSum(root.left, sum) + pathSum(root.right, sum) + help(root, sum);
};
var help = function(root, sum) {
if (root === null) return 0;
let res = 0;
if (root.val == sum) {
res++;
}
return help(root.left, sum - root.val) + help(root.right, sum - root.val) + res;
}
但是此方式的时间复杂度O(nlogn)
有一定的优化空间,考虑采用前缀和法,利用 JS 的 Map 这一数据结构,用路径和作 key,路径和出现的次数作 value。假设某一处的路径和为 x,往下搜索树至另一处它的路径和为 y。只要满足 y - x = sum 则总数增加,需要注意的是完成一次递归调用,需要将 map 中对应的路径和次数减 1,完整的代码如下:
var pathSum = function(root, sum) {
const map = new Map();
map.set(0, 1);
return help(root, 0, sum, map);
}
var help = function(root, sum, target, map) {
if (root === null) return 0;
sum += root.val;
let res = map.get(sum - target) || 0;
map.set(sum, (map.get(sum) || 0) + 1);
res += help(root.left, sum, target, map) + help(root.right, sum, target, map);
map.set(sum, map.get(sum) - 1);
return res;
}
这样的写法,时间复杂度为 O(n),可以看到速度提升了不少。
以上是关于二叉树的路径问题的主要内容,如果未能解决你的问题,请参考以下文章