Appearance
路径总和
leetcode-112:路径总和 I
leetcode-113:路径总和 II
leetcode-437:路径总和 III
路径总和 I
递归版本
js
// 递归版本
function hasPathSum(node, sum) {
if (!node) return false;
// 如果是叶子结点,则看该结点值是否等于剩下的 sum
if (node.left === null && node.right == null) {
return sum === node.value;
}
// 每次遍历一个结点都要减去自己的值后重新递归
const diff = sum - node.value;
return hasPathSum(node.left, diff) || hasPathSum(node.right, diff);
}
复杂度分析
时间复杂度:O(N),其中 N 是树的节点数。对每个节点访问一次。
空间复杂度:O(H),其中 H 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(N)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(logN)。
迭代版本
js
// 迭代版本,使用栈代替递归
function hasPathSum(root, sum) {
if (!root) return false;
const nodes = [root];
const values = [root.value];
while (0 < nodes.length) {
const node = nodes.pop();
const value = values.pop();
if (node.left === null && node.right === null && sum === value) {
return true;
}
if (node.left != null) {
nodes.push(node.left);
values.push(value + node.left.value);
}
if (node.right != null) {
nodes.push(node.right);
values.push(value + node.right.value);
}
}
return false;
}
复杂度分析
时间复杂度:O(N),其中 N 是树的节点数。对每个节点访问一次。
空间复杂度:O(H),其中 H 是树的高度。空间复杂度主要取决于队列的开销,队列中的元素个数不会超过树的节点数。栈的大小同样取决于二叉树的高度,但是对于栈的操作显然要比递归更加节省计算机资源。
路径总和 II
js
function pathSum(root, sum) {
const result = [];
if (!root) return result;
function helper(node, sum, paths) {
if (node.left === null && node.right === null) {
if (node.value === sum) {
paths.push(node.value);
result.push(paths.slice());
return;
}
return;
}
paths.push(node.value);
if (node.left) helper(node.left, sum - node.value, [...paths]);
if (node.right) helper(node.right, sum - node.value, [...paths]);
}
helper(root, sum, []);
return result;
}
如果每次递归都创建一个新的列表的话,会很浪费时间,所以我们对上面的代码加以改造,递归过程中,只需维护一个数组就可以。代码如下:
js
function pathSum(root, sum) {
const result = [];
if (!root) return result;
function helper(node, sum, paths, index) {
const value = node.value;
if (node.left === null && node.right === null) {
if (value === sum) {
paths[index] = value;
result.push(paths.slice(0, index + 1));
return;
}
return;
}
paths[index] = value;
if (node.left) helper(node.left, sum - value, paths, index + 1);
if (node.right) helper(node.right, sum - value, paths, index + 1);
}
helper(root, sum, [], 0);
return result;
}
js
// 迭代版本,使用栈代替递归
function pathSum(root, targetSum) {
const result = [];
if (!root) return result;
const nodes = [root];
const sums = [root.value];
const levels = [0];
const paths = [];
while (0 < nodes.length) {
const node = nodes.pop();
const sum = sums.pop();
const level = levels.pop();
paths[level] = node.value;
if (node.left === null && node.right === null && targetSum === sum) {
result.push(paths.slice(0, level + 1));
}
if (node.left) {
nodes.push(node.left);
sums.push(sum + node.left.value);
levels.push(level + 1);
}
if (node.right) {
nodes.push(node.right);
sums.push(sum + node.right.value);
levels.push(level + 1);
}
}
return result;
}
路径总和 III
js
function pathSum(root, sum) {
let result = 0;
if (!root) return result;
const stack = [root];
while (stack.length > 0) {
const node = stack.pop();
result += helper(node, sum);
if (node.left) stack.push(node.left);
if (node.right) stack.push(node.right);
}
function helper(node, sum) {
const value = node.value;
let result = 0;
if (sum === value) result += 1;
if (node.left) result += helper(node.left, sum - value);
if (node.right) result += helper(node.right, sum - value);
return result;
}
return result;
}