二叉树中两节点的最近公共父节点(360的c++一面问题)
面试官的问题:写一个函数 TreeNode* Find(TreeNode* root, TreeNode* p, TreeNode* q) ,返回二叉树中p和q的最近公共父节点。
本人反应:当时有点紧张,没怎么想就直接上手敲代码,一边想一边敲代码,越敲越想不出来,越想不出来越尴尬、越紧张...
鼓捣了十几分钟都没个头绪,面试官随意提示了两句,我感觉压力更大了... 就随便想了个思路就乱写(思维拐进了死胡同,弯路越走越远.......)
最后思路太跑偏了,就说了下当时脑子里很偏的思路,结果果然gg....
面试总共半小时左右就结束了: 开头的自我介绍就随便说了五分钟左右,没几句话就问了这个问题,结果思路跑偏,敲代码前前后后就二十多分钟,后面直接就“面试结束,你还有什么问题吗?”.... 我问了下工作相关的方向和地点,然后就彻底结束了....
下来自己仔细想了想,从递归的意义和原理入手,马上就有了思路... (哎,台上半小时都想不到,台下两分钟就有雏形了。还是得多面试面试,增强心理素质和脸皮厚度.......)
话不多说,直接上答案:
#define _CRT_SECURE_NO_WARNINGS //VS用scanf会报错,加了这个就ok了
#include<cstdio>
//360一面,二叉树中两节点的最近公共父节点
struct TreeNode{
int val;
TreeNode *left, *right;
TreeNode(int x = ) :val(x) { left = right = ; }
}*root; //为了测试方便,把p和q的类型改成int(面试现场可以不用改,直接敲完并描述思路就好吧)
//不然得直接比较两个指针的地址,先要取到二叉树中两个节点的地址太麻烦
TreeNode* Find(TreeNode* root, int p, int q) {
//递归先确定返回条件和返回值。
if (root == )return ; //没找到就一直到最底层,返回0
if (root->val == p || root->val == q)return root; //找到了就先返回自己,非0值 //其次应该根据递归的意义想到成功和失败的条件,及返回值
//先找左子树和右子树,下面的代码应该从底向上思考
TreeNode* a = Find(root->left, p, q);
TreeNode* b = Find(root->right, p, q);
//从底向上思考,先在底层执行,后在上层执行。
//当左边和右边各有一个时,显然成功,当前节点就是所求结果
if (a&&b)return root;
//当只有左边有一个时,答案在上层,先往上返回非0值
if (a)return a;
//当只有右边有一个时,答案在上层,先往上返回非0值
if (b)return b;
//左右都没有时,就返回0值
return ;
} //构建有tot-now+1个节点的树,从上到下、从左到右的编号为从now到tot
TreeNode* build(int now, int tot) {
if (now > tot)return ;
TreeNode* root = new TreeNode(now);
root->left = build(now * , tot);
root->right = build(now * + , tot);
return root;
} //delete掉new的全部内存空间
void deleteAll(TreeNode* root) {
if (root == )return;
deleteAll(root->left);
deleteAll(root->right);
delete root;
} int main() {
root = build(, );//构建4层的满二叉树
int a[][] = { {,},{,},{,},{,} };//4个测试样例
TreeNode* fa;
for (int i = ; i < ; i++) {
fa = Find(root, a[i][], a[i][]);
if (fa)printf("Common parent of (%d,%d) is %d\n", a[i][], a[i][], fa->val);
else printf("Common parent of (%d,%d) is NULL\n", a[i][], a[i][]);
} deleteAll(root);
return ;
}
证明算法的正确性:
构造了一个这样的二叉树: 1
2 3
4 5 6 7
8 9 10 11 12 13 14 15
1. 若p,q有一个是1(root节点),则会直接返回root,显然正确。
2. p,q的直接父节点相同时,p会返回非0,q会返回非0,所以直接父节点会返回本身,再上层会返回答案节点。 其他路径会搜索到最底层并返回0。
3. p,q的直接父节点不同时,p返回非0,上层都会返回非0;q会返回非0,上层都会返回非0。直到最近公共父节点会返回自己,再上层会返回答案节点。其他路径会搜索到最底层并返回0。
此算法没有使用二叉树中节点之间的任何关系,直接递归遍历整棵树,以值(或地址)相等为返回条件,通用性非常强。
用在节点间有特殊关系的情况下,还可以利用节点间的关系(大小等)进行剪枝,使其他路径无需搜索到最底层就提前返回。
二叉树中两节点的最近公共父节点(360的c++一面问题)的更多相关文章
- LeetCode 236 Lowest Common Ancestor of a Binary Tree 二叉树两个子节点的最低公共父节点
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode ...
- 笔试算法题(24):找出出现次数超过一半的元素 & 二叉树最近公共父节点
出题:数组中有一个数字出现的次数超过了数组长度的一半,请找出这个数字: 分析: 解法1:首先对数组进行排序,时间复杂度为O(NlogN),由于有一个数字出现次数超过了数组的一半,所以如果二分数组的话, ...
- LeetCode 二叉树,两个子节点的最近的公共父节点
LeetCode 二叉树,两个子节点的最近的公共父节点 二叉树 Lowest Common Ancestor of a Binary Tree 二叉树的最近公共父亲节点 https://leetcod ...
- LCA最小公共父节点的解题思路
LCA最小公共父节点解法: 1.二叉搜索树: 中序遍历是升序,前序遍历即按序插入建树的序列. 二叉搜索树建树最好用前序+中序,如果用前序建树,最坏情况会退化为线性表,超时. 最近公共祖先甲级: A11 ...
- 剑指Offer(第二版)面试案例:树中两个节点的最低公共祖先节点
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/74612786冷血之心的博客) 剑指Offer(第二版)面试案例:树 ...
- [LeetCode] 1123. Lowest Common Ancestor of Deepest Leaves 最深叶结点的最小公共父节点
Given a rooted binary tree, return the lowest common ancestor of its deepest leaves. Recall that: Th ...
- MySQL 树形结构 根据指定节点 获取其所有父节点序列
背景说明 需求:MySQL树形结构, 根据指定的节点,获取其所有父节点序列. 问题分析 1.可以使用类似Java这种面向对象的语言,对节点集合进行逻辑处理,获取父节点. 2.直接自定义MySQL函数 ...
- Sprite子节点透明度不能跟随父节点变化的问题求解(转)
原出处忘记了. [已解决]Sprite子节点透明度不能跟随父节点变化的问题求解 自己封装了一个按钮控件,点击的时候封装了一些动作,其中有透明度的变化. 当点击发生的时候,Sprite本体执行正常,但是 ...
- Angular项目中迭代生成的树,激活选中的节点,并将节点数据发送到父节点
从后台返回的数据,还有多层子节点,需要一个生成树的组件,如果直接在页面上写循环来拼接感觉会很麻烦,因为数据的层级结构不固定. 参考网上其他人的方法,整理如下: 1. 创建一个用于循环迭代的组件,在父组 ...
随机推荐
- ajax的封装——jq简化版
最近在复习ajax的知识,练习了下ajax的封装,此处做下笔记 废话不多说,直接代码 //发请求 //此处的url为请求地址,type为请求方式,success为请求成功的回调函数 myaxios({ ...
- Ubuntu添加新用户并给普通用户赋予root新权限
添加新用户 首先用adduser命令添加普通用户: #adduser newusername 只有在root权限才可以添加新用户 修改密码: #passwd username 赋予root权限 方法1 ...
- 读者来信 | 刚搭完HBase集群,Phoenix一启动,HBase就全崩了,是什么原因?(已解决)
前言:之前有朋友加好友与我探讨一些问题,我觉得这些问题倒挺有价值的:于是就想在本公众号开设一个问答专栏,方便技术交流与分享,专栏名就定为:<读者来信>.如遇到本人能力有限难以解决的问题,我 ...
- linux中的bash
一.bash的简介 操作系统都是需要通过shell跟内核来交互的,常见的shell有GUI.KDE.sh.csh.bash.tsh.zsh等. 而linux中最常用的shell就是bash. 二.ba ...
- python数据分析工具 | matplotlib
不论是数据挖掘还是数学建模,都免不了数据可视化的问题.对于 Python 来说,matplotlib 是最著名的绘图库,它主要用于二维绘图,当然也可以进行简单的三维绘图.它不但提供了一整套和 Matl ...
- 在vue项目中封装echarts的正确姿势
为什么需要封装echarts 每个开发者在制作图表时都需要从头到尾书写一遍完整的option配置,十分冗余 在同一个项目中,各类图表设计十分相似,甚至是相同,没必要一直做重复工作 可能有一些开发者忘记 ...
- Python机器学习笔记 集成学习总结
集成学习(Ensemble learning)是使用一系列学习器进行学习,并使用某种规则把各个学习结果进行整合,从而获得比单个学习器显著优越的泛化性能.它不是一种单独的机器学习算法啊,而更像是一种优 ...
- JDK常用命令行工具使用
- sNews1.7在wamp上的部署及运行
安装前的准备 Apache Server 必须开启 mod_rewrite 模块 MySQL 数据库版本在 4.x以上 PHP: >= 4.x 并且 <=5.6 1.我使用的是wampse ...
- Spring Taco Cloud——design视图的创建(含thymeleaf模板遇到的一些小问题)
先来看下综合前两篇内容加上本次视图的成果 可能不是很美观,因为并没有加css样式,我想等整个项目有个差不多的功能实现后再进行页面优化,请谅解 下面我贴上自己定义修改过的Taco的design视图代 ...