更快的求最近公共祖先(LCA)的算法-倍增法求LCA

这篇具有很好参考价值的文章主要介绍了更快的求最近公共祖先(LCA)的算法-倍增法求LCA。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

leetcode 题目

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

参考:最近公共祖先

思路

f a [ i ] [ j ] \rm{fa}[i][j] fa[i][j] 表示结点 i i i的第 2 i 2^i 2i个组先
d e p [ i ] \rm{dep}[i] dep[i] 表示结点 i i i的深度
n e x t [ i ] [ 0 ] \rm{next}[i][0] next[i][0] 表示结点 i i i的左子结点
n e x t [ i ] [ 1 ] \rm{next}[i][1] next[i][1] 表示结点 i i i的右子结点

特别地,

  • i = 0 表示一个不存在的结点
  • i = 1 表示树的根结点
  • fa[i][0] 表示结点i的父节点

首先,通过树的深度优先遍历,计算fa和dep数组。
假定要求x和y两个结点的最近公共祖先,那么通过fa快速把x,y调整到一样的高度。然后分两种情况:

  • 如果此时x = y, 则已经找到最近公共祖先
  • 否则,通过fa找到最近公共祖先之下,第一个不是它们祖先的点。它们的父节点即是最近公共祖先。

复杂度分析

假设有n个结点
预处理:每个节点至多有 log ⁡ n \log n logn个父节点,因此时间复杂度为 T ( n ) = O ( n ⋅ log ⁡ n ) T(n) = O(n \cdot \log n) T(n)=O(nlogn)
查找:从上到下调平以从下到上找第一个共公祖先,最多 O ( log ⁡ n ) O(\log n) O(logn)次,因此时间复杂度为 T ( n ) = O ( log ⁡ n ) T(n)=O(\log n) T(n)=O(logn)文章来源地址https://www.toymoban.com/news/detail-653418.html

代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int[][] fa;
    int[] dep; 
    int[][] next;

    public void dfs(int node, int p){
        if(node != 0){
            fa[node][0] = p;
            dep[node] = dep[p] + 1;
            for(int i = 1; i < 31; i++){
                fa[node][i] = fa[fa[node][i-1]][i-1];
            }
            dfs(next[node][0], node);
            dfs(next[node][1], node);
        } 
    }

    public int lca(int x, int y){
        if(dep[x] > dep[y]) {
            int t = x; x = y; y = t;
        }
        int tmp = dep[y] - dep[x];
        int weight = 0;
        // 从下往上把两者高度调成一样
        while(tmp > 0){
            if((tmp & 1) == 1){
                y = fa[y][weight];
            }
            tmp >>= 1;
            weight ++;
        }
        // 如果相等,则已经找到答案
        if(x == y) return x;
        // 从上往下找到第一个非公共的
        for(int i = 30; i >= 0 && x != y; i--){
            if(fa[x][i] != fa[y][i]){
                x = fa[x][i];
                y = fa[y][i];
            }
        }
        return fa[x][0];
    }


    HashMap<TreeNode, Integer> map = new HashMap<>();
    ArrayList<TreeNode> arr = new ArrayList<>();
    int index = 0;
    public void proceed(TreeNode root){
        if(root != null){
            map.put(root, ++index);
            arr.add(root);
            proceed(root.left);
            proceed(root.right);
        }
    }

    public void proceed2(TreeNode root){
        if(root != null){
            next[map.get(root)][0] = map.get(root.left);
            next[map.get(root)][1] = map.get(root.right);
            proceed2(root.left);
            proceed2(root.right);
        }
    }

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        map.put(null, 0);
        arr.add(null);
        proceed(root);
        fa = new int[arr.size()][31];
        dep = new int[arr.size()];
        next = new int[arr.size()][2];
        proceed2(root);
        dfs(1, 0);
        return arr.get(lca(map.get(p), map.get(q)));
    }
}

到了这里,关于更快的求最近公共祖先(LCA)的算法-倍增法求LCA的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法与数据结构】236、LeetCode二叉树的最近公共祖先

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 : 根据定义,最近祖先节点需要遍历节点的左右子树,然后才能知道是否为最近祖先节点。 那么这种需求是先遍历左右节点,然后遍历中间节点,属于左右中的后序遍历模式 。因此

    2024年02月09日
    浏览(38)
  • DAY23:二叉树(十三)二叉树的最近公共祖先+二叉搜索树的最近公共祖先

    一定要仔细看 提示 ,二叉树 数值不重复 ,意味着后序遍历不会存在两边找到了同个元素的情况 本题需要进一步理解后序遍历, 可以认为后序遍历在\\\"深入\\\"到每个子树的最深层之后,才开始\\\"回溯\\\"并访问节点 。 在某种意义上,这可以被视为从下往上的遍历方式 , 但需要注

    2024年02月09日
    浏览(44)
  • 算法刷题Day 21 二叉搜索树的最小绝对差+二叉搜索树中的众数+二叉树的最近公共祖先

    递归 递归中保存前一个节点的指针的方法,需要再学习,巩固一下 迭代 一下子就想到的方法:遍历一遍二叉搜索树,把各个节点的值存进哈希表里(节点值——键,出现频率——值),再遍历哈希表找众数 一般方法 既然是二叉搜索树,中序遍历就是有序的。有序的话,我

    2024年02月16日
    浏览(44)
  • 「学习笔记」tarjan求最近公共祖先

    Tarjan 算法是一种 离线算法 ,需要使用并查集记录某个结点的祖先结点。 并没有传说中的那么快。 将询问都记录下来,将它们建成正向边和反向边。 在 dfs 的过程中,给走过的节点打上标记,同时维护并查集,这里利用了回溯的思想,如果 (u) 节点的这棵子树没搜完,那么

    2024年02月01日
    浏览(40)
  • 「学习笔记」tarjan 求最近公共祖先

    Tarjan 算法是一种 离线算法 ,需要使用并查集记录某个结点的祖先结点。 并没有传说中的那么快。 将询问都记录下来,将它们建成正向边和反向边。 在 dfs 的过程中,给走过的节点打上标记,同时维护并查集,这里利用了回溯的思想,如果 (u) 节点的这棵子树没搜完,那么

    2024年02月01日
    浏览(50)
  • 力扣236——二叉树的最近公共祖先

    祝大家新年快乐呀,虽这段时间正值过年,但是我们不要忘记停下学习的脚步。今天我们一起看一到力扣上的经典二叉树OJ题,求二叉树两个结点最近的公共祖先。 https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/ 链接给大家放在这里啦,大家一点即达 首先我们

    2024年02月20日
    浏览(43)
  • leetcode 236. 二叉树的最近公共祖先

            这道题是道面试高频题,并且有点抽象。         首先确定终止条件。如果根节点为空,或者其中一个节点是根节点本身(即 p == root 或 q == root ),那么根节点就是它们的最低共同祖先,因此我们直接返回根节点 root 。          接下来,递归调用 lowestComm

    2024年02月15日
    浏览(38)
  • 【算法第十七天8.1】530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先

    链接 力扣530-二叉搜索树的最小绝对差 思路 链接 力扣501-二叉搜索树中的众数 思路 链接 力扣236.二叉树的最近公共祖先 思路

    2024年02月14日
    浏览(47)
  • 算法刷题Day 22 二叉搜索树的最近公共祖先+二叉搜索树中的插入操作+删除二叉搜索树中的节点

    根据二叉搜索树的性质,相比普通二叉树可以极大程度的简化代码,作为公共祖先其值一定在两个给定节点值之间,从树根往下遍历,第一次出现两个给定节点值之间的值,那个节点即为最近公共祖先(为什么是最近不是最远?根节点一般为最远,第一次出现的值处于两个给

    2024年02月17日
    浏览(43)
  • leetcode热题100. 二叉树的最近公共祖先

    Problem: 236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先

    2024年01月19日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包