Given a binary tree where every node has a unique value, and a target key k, find the value of the nearest leaf node to target k in the tree.

Here, nearest to a leaf means the least number of edges travelled on the binary tree to reach any leaf of the tree. Also, a node is called a leaf if it has no children.

In the following examples, the input tree is represented in flattened form row by row. The actual root tree given will be a TreeNode object.

Example 1:

Input:
root = [1, 3, 2], k = 1
Diagram of binary tree:
1
/ \
3 2 Output: 2 (or 3) Explanation: Either 2 or 3 is the nearest leaf node to the target of 1.

Example 2:

Input:
root = [1], k = 1
Output: 1 Explanation: The nearest leaf node is the root node itself.

Example 3:

Input:
root = [1,2,3,4,null,null,null,5,null,6], k = 2
Diagram of binary tree:
1
/ \
2 3
/
4
/
5
/
6 Output: 3
Explanation: The leaf node with value 3 (and not the leaf node with value 6) is nearest to the node with value 2.

Note:

  1. root represents a binary tree with at least 1 node and at most 1000 nodes.
  2. Every node has a unique node.val in range [1, 1000].
  3. There exists some node in the given binary tree for which node.val == k.

这道题让我们找二叉树中最近的叶结点,叶结点就是最底端没有子结点的那个。我们观察题目中的例子3,发现结点2的最近叶结点是其右边的那个结点3,那么传统的二叉树的遍历只能去找其子结点中的叶结点,像这种同一层水平的结点该怎么弄呢?我们知道树的本质就是一种无向图,但是树只提供了父结点到子结点的连接,反过来就不行了,所以只要我们建立了反向连接,就可以用BFS来找最近的叶结点了。明白了这一点后,我们就先来做反向连接吧,用一个哈希map,建立子结点与其父结点之间的映射,其实我们不用做完所有的反向连接,而是做到要求的结点k就行了,因为结点k的子结点可以直接访问,不需要再反过来查找。我们用DFS来遍历结点,并做反向连接,直到遇到结点k时,将其返回。此时我们得到了结点k,并且做好了结点k上面所有结点的反向连接,那么就可以用BFS来找最近的叶结点了,将结点k加入队列queue和已访问集合visited中,然后开始循环,每次取出队首元素,如果是叶结点,说明已经找到了最近叶结点,直接返回;如果左子结点存在,并且不在visited集合中,那么先将其加入集合,然后再加入队列,同理,如果右子结点存在,并且不在visited集合中,那么先将其加入集合,然后再加入队列;再来看其父结点,如果不在visited集合中,那么先将其加入集合,然后再加入队列。因为题目中说了一定会有结点k,所以在循环内部就可以直接返回了,不会有退出循环的可能,但是为表尊重,我们最后还是加上return -1吧, 参见代码如下:

解法一:

class Solution {
public:
int findClosestLeaf(TreeNode* root, int k) {
unordered_map<TreeNode*, TreeNode*> back;
TreeNode *kNode = find(root, k, back);
queue<TreeNode*> q{{kNode}};
unordered_set<TreeNode*> visited{{kNode}};
while (!q.empty()) {
TreeNode *t = q.front(); q.pop();
if (!t->left && !t->right) return t->val;
if (t->left && !visited.count(t->left)) {
visited.insert(t->left);
q.push(t->left);
}
if (t->right && !visited.count(t->right)) {
visited.insert(t->right);
q.push(t->right);
}
if (back.count(t) && !visited.count(back[t])) {
visited.insert(back[t]);
q.push(back[t]);
}
}
return -;
}
TreeNode* find(TreeNode* node, int k, unordered_map<TreeNode*, TreeNode*>& back) {
if (node->val == k) return node;
if (node->left) {
back[node->left] = node;
TreeNode *left = find(node->left, k, back);
if (left) return left;
}
if (node->right) {
back[node->right] = node;
TreeNode *right = find(node->right, k, back);
if (right) return right;
}
return NULL;
}
};

下面这种解法也挺巧妙的,虽然没有像上面的解法那样建立所有父结点的反向连接,但是这种解法直接提前算出来了所有父结点到结点k的距离,就比如说例子3中,结点k的父结点只有一个,即为结点1,那么算出其和结点k的距离为1,即建立结点1和距离1之间的映射,另外建立结点k和0之间的映射,这样便于从结点k开始像叶结点统计距离。接下来,我们维护一个最小值mn,表示结点k到叶结点的最小距离,还有结果res,指向那个最小距离的叶结点。下面就开始再次遍历二叉树了,如果当前结点为空, 直接返回。否则先在哈希map中看当前结点是否有映射值,有的话就取出来(如果有,则说明当前结点可能k或者其父结点),如果当前结点是叶结点了,那么我们要用当前距离cur和最小距离mn比较,如果cur更小的话,就将mn更新为cur,将结果res更新为当前结点。否则就对其左右子结点调用递归函数,注意cur要加1,参见代码如下:

解法二:

class Solution {
public:
int findClosestLeaf(TreeNode* root, int k) {
int res = -, mn = INT_MAX;
unordered_map<int, int> m;
m[k] = ;
find(root, k, m);
helper(root, -, m, mn, res);
return res;
}
int find(TreeNode* node, int k, unordered_map<int, int>& m) {
if (!node) return -;
if (node->val == k) return ;
int r = find(node->left, k, m);
if (r != -) {
m[node->val] = r;
return r + ;
}
r = find(node->right, k, m);
if (r != -) {
m[node->val] = r;
return r + ;
}
return -;
}
void helper(TreeNode* node, int cur, unordered_map<int, int>& m, int& mn, int& res) {
if (!node) return;
if (m.count(node->val)) cur = m[node->val];
if (!node->left && !node->right) {
if (mn > cur) {
mn = cur;
res = node->val;
}
}
helper(node->left, cur + , m, mn, res);
helper(node->right, cur + , m, mn, res);
}
};

参考资料:

https://leetcode.com/problems/closest-leaf-in-a-binary-tree/

https://leetcode.com/problems/closest-leaf-in-a-binary-tree/discuss/109960/java-dfs-bfs-27ms

https://leetcode.com/problems/closest-leaf-in-a-binary-tree/discuss/109963/java-short-solution28-ms-solution

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Closest Leaf in a Binary Tree 二叉树中最近的叶结点的更多相关文章

  1. Leetcode: Closest Leaf in a Binary Tree

    Given a binary tree where every node has a unique value, and a target key k, find the value of the n ...

  2. [LeetCode] Second Minimum Node In a Binary Tree 二叉树中第二小的结点

    Given a non-empty special binary tree consisting of nodes with the non-negative value, where each no ...

  3. Leetcode671.Second Minimum Node In a Binary Tree二叉树中的第二小结点

    给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0.如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值. 给出这样的一个二叉树,你需要输出所有节点中 ...

  4. [LeetCode] 111. Minimum Depth of Binary Tree 二叉树的最小深度

    Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...

  5. 【LeetCode】Minimum Depth of Binary Tree 二叉树的最小深度 java

    [LeetCode]Minimum Depth of Binary Tree Given a binary tree, find its minimum depth. The minimum dept ...

  6. [LeetCode] 111. Minimum Depth of Binary Tree ☆(二叉树的最小深度)

    [Leetcode] Maximum and Minimum Depth of Binary Tree 二叉树的最小最大深度 (最小有3种解法) 描述 解析 递归深度优先搜索 当求最大深度时,我们只要 ...

  7. LeetCode 742. Closest Leaf in a Binary Tree

    原题链接在这里:https://leetcode.com/problems/closest-leaf-in-a-binary-tree/ 题目: Given a binary tree where e ...

  8. [LeetCode] 104. Maximum Depth of Binary Tree 二叉树的最大深度

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  9. [LeetCode] Average of Levels in Binary Tree 二叉树的层平均值

    Given a non-empty binary tree, return the average value of the nodes on each level in the form of an ...

随机推荐

  1. [css 实践篇] 解决悬浮的<header> <footer>遮挡内容的处理技巧

    我写的实践篇 都是自己在实践项目所遇到的 "拦路虎" 还是很有借鉴的意义的.(实践才是检验真理的唯一标准呀),废话不多说,进去正题 position: fixed 绝对固定底部后会 ...

  2. WPF学习笔记2

    XML语言中添加注释为<!---->,这是和C#不同的,但是和HTML十分相似. XAML是一种基于XML的标记语言,每一个XML元素代表.NET控件的一个对象,XML元素的属性可以是.N ...

  3. ORACLE 监听

    今天来学习一下监听的相关内容,昨晚被老大问了两个关于监听很简单的问题,但是却吞吞吐吐回答,而且有一个问题还答错了,刚刚查了下资料,才发现"驴头对了马嘴",哭笑不得. 一.监听(li ...

  4. oracle、导出、导入

    一.数据库导入: No1.查询所有表中那些是空表. select table_name from user_tables where NUM_ROWS=0; No2.拼接字符串生成SQL执行语句. s ...

  5. 指令-arModal-点击提示框模板

    html 使用<ar-modal></ar-modal>: <ar-modal modal-obj="modalObj" ok="newAl ...

  6. 【Alpha 阶段】后期测试及补充(第十一、十二周)

    [Alpha 阶段]动态成果展示 修复了一些bug后,关于游戏的一些动态图展示如下: 终极版需求规格说明书和代码规范 经过一些细微的图片和格式的调整,完成了本学期的最终版本: [markdown版说明 ...

  7. alpha-咸鱼冲刺day2

    一,合照 emmmmm.自然是没有的. 二,项目燃尽图 三,项目进展 今天并没有什么进展,弄了好久好像也只研究出怎么把JS的功能块插入进去.html的信息提交这些还不知道要怎么弄. 四,问题困难 日常 ...

  8. SQL函数返回表的示例-Z

    create function [dbo].[GetOperateCustGroup] ( ), ) ) returns @TempTable table (MaxPrice float,MinPri ...

  9. 1013团队Beta冲刺day1

    项目进展 李明皇 今天解决的进度 点击首页list相应条目将信息传到详情页 明天安排 优化信息详情页布局 林翔 今天解决的进度 前后端连接成功 明天安排 开始微信前端+数据库写入 孙敏铭 今天解决的进 ...

  10. Python IDE Spyder的简单介绍

    最近深度学习发展非常迅猛,大有一统江湖的趋势.经过一段时间学习,发现自己对这种神奇的玄学非常感兴趣,希望能够进一步的研究.而这种研究性学科单纯地看论文比较难以明白,所以希望能够跟进大牛们写的代码深入学 ...