「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」
给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。
返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。
示例 1:
输入:root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2
输出:[7,4,1]
解释:
所求结点为与目标结点(值为 5)距离为 2 的结点,
值分别为 7,4,以及 1
注意,输入的 "root" 和 "target" 实际上是树上的结点。
上面的输入仅仅是对这些对象进行了序列化描述。
深度优先搜索 + 哈希表
若将 当作树的根结点,我们就能从 出发,使用深度优先搜索去寻找与 距离为 k 的所有结点,即深度为 k 的所有结点。
由于输入的二叉树没有记录父结点,为此,我们从根结点 root 出发,使用深度优先搜索遍历整棵树,同时用一个哈希表记录每个结点的父结点。
然后从 出发,使用深度优先搜索遍历整棵树,除了搜索左右儿子外,还可以顺着父结点向上搜索。
代码实现时,由于每个结点值都是唯一的,哈希表的键可以用结点值代替。此外,为避免在深度优先搜索时重复访问结点,递归时额外传入来源结点 ,在递归前比较目标结点是否与来源结点相同,不同的情况下才进行递归。
var distanceK = function(root, target, k) {
const parents = new Map();
const ans = [];
const findParents = (node) => {
if (node.left != null) {
parents.set(node.left.val, node);
findParents(node.left);
}
if (node.right != null) {
parents.set(node.right.val, node);
findParents(node.right);
}
}
// 从 root 出发 DFS,记录每个结点的父结点
findParents(root);
const findAns = (node, from, depth, k) => {
if (node == null) {
return;
}
if (depth === k) {
ans.push(node.val);
return;
}
if (node.left !== from) {
findAns(node.left, node, depth + 1, k);
}
if (node.right !== from) {
findAns(node.right, node, depth + 1, k);
}
if (parents.get(node.val) !== from) {
findAns(parents.get(node.val), node, depth + 1, k);
}
}
// 从 target 出发 DFS,寻找所有深度为 k 的结点
findAns(target, null, 0, k);
return ans;
};
复杂度分析
- 时间复杂度:,其中 是二叉树的结点个数。需要执行两次深度优先搜索,每次的时间复杂度均为 。
- 空间复杂度:。记录父节点需要 的空间,深度优先搜索需要 的栈空间。