注意:这篇文章需要你了解C++作为前置

题目描述:

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”

        _______3______/                       \_5__                 ___1__/        \             /           \
6         _2_       0              8/       \7          4

For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.

Subscribe to see which companies asked this question

解题思路

这个题目是一个最为简单的LCA问题,只需要查询一对节点(u, v)的公共祖先,所以实际上不需要使用用到了什么需要先验知识才能解决的算法

下面是一个最为基础的思路:

简单粗暴法

可以很轻松的想到一对节点(u, v)的公共祖先满足下述可能中的某一种:

1. x in (u, v) 为 (u, v) 的LCA;

2. x not in (u, v) 为 (u, v) 的LCA 此时易证明 u, v 分置该祖先的左右两子树中;

所以可以很清楚的看出这个问题可以直接使用遍历的方法来查找LCA

然后注意到需要通过左子树和右子树才能确定LCA,所以应该使用后序遍历:

代码如下:

class Solution
{
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {LCA = u = v = L = R = NULL;u = p;v = q;//init
            DFS(root);return LCA;}void DFS(TreeNode* root){if(root == NULL || LCA != NULL){return;}if(root->left != NULL){DFS(root->left);if(root->left == L)L = root;if(root->left == R)R = root;//update L, R to its father
            }if(root->right != NULL){DFS(root->right); if(root->right == L)L = root;if(root->right == R)R = root;//update L, R to its father
            }if(root == u)L = root; // first update of Lif(root == v)R = root;// first update of Rif(L != NULL && R != NULL && L == R && LCA == NULL){ //has find  LCALCA = L; return;}}// recursion function updating LCATreeNode* L;TreeNode* R;TreeNode* LCA;TreeNode* u;TreeNode* v;};           

没什么好说的,肯定能优化,但是这样反正过这题没问题。

但是,LCA问题本来就不是这么简单的玩意

实际上,LCA问题的初始用意是要快速处理多起LCA询问

设询问次数Q,这个朴素算法复杂度为O(QN),跟咸鱼有什么区别

相信院系里其他人也都知道LCA的本来面目是什么样的

然而,这些算法都需要一些先验知识

下面介绍一个比较常用的离线算法: Tarjan算法

Tarjan算法

离线算法:在开始时就需要知道问题的所有输入数据的算法

根据复杂度分析,Tarjan算法对于LCA问题的复杂度为O(N + Q),远优于朴素法

这个算法利用了并查集的特性,节省了空间和时间

为了一次性解决所有需求,为每一个节点分配一块空间来存储针对该节点的询问

(实际上也有别的方式能够解决这个问题,为了简便使用这个方法存储)

由于在朴素法中提出的那些关于解的条件依然成立

所以依然采用后序顺序访问树

当其子节点的访问结束后再处理针对该节点的所有请求

又由于可能在存储的询问(u, v)在访问u 时尚无法求解,如:

          _______3______/                       \_5__                  ___1__/        \             /            \
6         _2_        0               8/        \7          4针对(7, 8)的查询在访问7时是无法求解的

大概的思路是这样的

建立所有节点的并查集:用并查集所有节点中最顶层的节点作为并查集的代表,初始化时所有节点所在的并查集都只包含它本身

DFS访问

当访问到的节点有一支子树访问结束后,将这支子树的并查集归并到该节点所在的并查集

当两支子树都被归并到该节点所在的并查集中时,开始处理针对该节点的请求,设当前节点为u, 另一节点为v

仅处理v已被访问时的请求

此时我们有了这样的一个事实:

设当前节点为u, 另一节点为v

如果有针对(u ,v)的请求在u节点被处理了,那么在u之前,询问的另一个节点v已经被访问过了

根据后续遍历的特性,此时v所在的并查集的代表就是(u, v)的LCA

并查集的实现通过一个映射f[n]实现, f[n] 指向n的上一层并查集代表,如果n为顶层并查集,则f[n] = n

这样的话并查集的合并仅需要更改f[n] 就可以实现

最后说两句

支线任务什么的,其实我都看过,也都做过一遍,但我加上这篇也只写了两篇随笔,原因也是挺简单的:

我觉得那些我没写的题目讲起来真的不知道能讲什么

比如第一次的题目 ,你只要想到对链表原地反转,这一点就足够解决问题了

第二次的题目是上课的原题

第三次还算有点意思,需要考虑栈的特性

这一次给了道裸题,直接就是LCA

其实这些题目离答案非常近,也没有什么需要抽象的内容

这样的题目能讲些什么呢?

画个图一步一步教你走路?

能讲的东西我觉得只有一两句话,这一两句话也就够了

最后的最后

你是一个小有名气的冒险者导师

城门口的各种怪物,你徒手都能解决

有一天,冒险者协会给了你一个任务

写一个新手专栏:

傻瓜也能看懂的指南:一步一步干掉史莱姆

为了完成它

你拿着剑,游荡在城镇门口,日复一日

把这种黏液组成的杂兵砍碎了一遍又一遍

只为了你能得到的报酬从两百银币变成三百银币

为了这一百银币

你绞尽脑汁,不停地回忆自己出剑的角度,砍上去的手感,切入的深度,造成的伤害,史莱姆躲闪的方向,把这些详细得令人发指的细节写进书里

新手看着指南,将史莱姆砍杀得七零八落,很开心

你拿着手上的钱袋,想着晚上能去酒馆喝两杯,也很开心

看似如此

————

但在无人的夜里

你有时还是会想

这件工作的意义何在?

新手们会满足于史莱姆么?

我为什么不让他们看看更遥远的世界?

于是终于有一天,你放弃了城门外的史莱姆

走向荒野深处,那里是你冒险的地方

你看到喷吐硫磺,火焰和毒气的巨龙

你看到长有巨大触须,操纵邪能的灵吸怪

你看到双头独眼,如山岳般高大的戈隆

这些你的老对手,你以前的敌人

你手里的剑因为你的紧握而发热

你早已遗忘的兴奋感也涌了出来

————

你费劲千辛万苦,打倒了巨龙,无面者与戈隆

兴冲冲的把自己的经历写到了你的专栏里

告诉新手

还有一些怪物,是这样的

它们很强大,也很棘手

你用来杀死史莱姆的剑术,经过一系列的修正,加强,也能够干掉这些怪物

但你得学习这些剑术技巧,这里我无法详细介绍

而冒险者协会的回应是:后面附上的拓展游记有点意思,但我们觉得新手只想知道如何精确杀死史莱姆,越详细越好

————

————

转载于:https://www.cnblogs.com/ocNflag/p/4967695.html

LeetCode-236的解法和延伸相关推荐

  1. 力扣(LeetCode)236. 二叉树的最近公共祖先(C语言)

    一.环境说明 本文是 LeetCode 236. 二叉树的最近公共祖先,使用c语言实现. 递归. 测试环境:Visual Studio 2019. 二.代码展示 精简代码: struct TreeNo ...

  2. LeetCode单词规律解法

    LeetCode单词规律解法 给定一种规律 pattern 和一个字符串 str ,判断 str 是否遵循相同的规律. 这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 str ...

  3. leetcode 236. 二叉树的最近公共祖先 递归解法 c语言

    如题: 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先.百度百科中最近公共祖先的定义为:"对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x, 满足 x 是 p.q ...

  4. LeetCode 236. 二叉树的最近公共祖先

    文章目录 解法1:保存祖先节点+逐个判断 解法2:深度优先遍历 解法3:记录祖先节点 https://leetcode-cn.com/problems/lowest-common-ancestor-o ...

  5. Leetcode算法题-解法转载

    版权声明:本文为博主原创文章,未经博主允许不得转载.    https://blog.csdn.net/fuxuemingzhu/article/details/85112591 作者: 负雪明烛 i ...

  6. 【一天一道Leetcode】基本计算器的延伸问题

    本篇推文共计2000个字,阅读时间约3分钟. 01 题目描述 题目描述: 给你一个字符串表达式s,请你实现一个基本计算器来计算并返回它的值. 整数除法仅保留整数部分. 示例: 输入:s = " ...

  7. leetcode 236. Lowest Common Ancestor of a Binary Tree | 236. 二叉树的最近公共祖先(Java)

    题目 https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/ 题解 思路来源:左程云<程序员代码面试指南&g ...

  8. [leetcode]236.二叉树的最近公共祖先

    给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p.q,最近公共祖先表示为一个节点 x,满足 x 是 p.q 的祖先且 ...

  9. Leetcode上的解法看不懂?试着用动画的方式去辅助理解

    推荐一个用动画的方式演示leetcode题目解题思路的github仓库: https://github.com/MisterBooo/LeetCodeAnimation 超过15000个star: 用 ...

  10. 【LeetCode之C#解法】 移动零、爬楼梯

    题目官网链接 https://leetcode-cn.com/problems/move-zeroes/ 283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非 ...

最新文章

  1. linux wc命令参数及用法详解
  2. 题目1184:二叉树遍历
  3. Android开发系统版本的区别,开发者对比安卓和iOS系统
  4. LeetCode-66. 托普利茨矩阵
  5. 第二次作业动手动脑的解答
  6. SpringBootSwagger构建REST API并生成API文档
  7. Notepad++ 查找替换 换行符的方法
  8. 递归法:整数划分问题(怎么进行划分呢)
  9. webpack.config.js====CSS相关:插件optimize-css-assets-webpack-plugin
  10. jq监听子元素被点击_jQuery怎么实现当前被点击元素的父级下的某个元素显示出来了?...
  11. windows7 android 驱动,Windows7安卓刷机驱动安装教程图文详解
  12. 编译器之词法分析器(Lexical Analyzer)
  13. m7405d粉盒清零方法_联想m7605d清零方法
  14. 91位图和bigemap大地图的区别
  15. mySQL数据库学习的一些心得
  16. adb 连接方式汇总
  17. 精准电流走向分析|用笔记本电脑的供电电路描述MOS管的两大功能:开关作用和隔离功能
  18. 安卓蓝牙实现即时通讯功能
  19. 洛谷P4942 小凯的数字
  20. MySql数据库记录相差14小时排错,使用Java访问Mysql数据库时出现时区异常的解决方案

热门文章

  1. 魔兽怀旧服联盟服务器不稳定,魔兽世界怀旧服上次被联盟攻击至少三个月前,“单边服”何去何从...
  2. 江西智汇网络推客SCRM智能获客系统客户倍增的全员营销系统
  3. 学习模式上的记录之统计篇二 Sigmaplot 非线性回归报告分析
  4. 用web audio api 在canvas上画出音频的音轨
  5. 创建选区快捷键是什么_Photoshop选区操作的快捷键
  6. Markdown基本语法和Typora使用教程
  7. 找计算机专业老师的说说,学生想念老师的说说 思念老师的唯美句子
  8. 批量处理word所有回车行
  9. Deepfashion2数据集
  10. Quard SPI和QPI的区别