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

news/2024/7/24 7:29:26 标签: 算法

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)

代码

/**
 * 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)));
    }
}


http://www.niftyadmin.cn/n/4943532.html

相关文章

【贪心+二分】CF1791G2

Problem - 1791G2 - Codeforces 题意&#xff1a; 思路&#xff1a; 首先&#xff0c;模拟一下样例发现&#xff0c;第一次传送之后&#xff0c;每次传送的贡献都是独立的&#xff0c;每次的贡献都是 min(ai i, ai n - i 1)&#xff0c;因此根据这个贪心即可 贪心无非两…

【QT】 QFileQFileInfo文件操作

很高兴在雪易的CSDN遇见你 &#xff0c;给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享QT对文件的操作技术&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xff0c;一起进步&#xff01; 你的点…

自动化安装系统(一)

系统安装过程 加载boot loader加载启动安装菜单加载内核和initrd文件加载根系统运行anaconda的安装向导 安装光盘中与安装相关的文件 安装autofs启动后会自动出现/misc目录。 在虚拟机设置中添加CD/DVD&#xff0c;使用系统ISO文件&#xff0c;登录系统后mount /dev/cdrom …

Docker安装nacos v2.1.1

目录 前言安装nacos安装步骤1&#xff1a;准备1. 安装docker2. 搜索可以使用的镜像。3. 选择合适的redis镜像。3. 也可从docker hub上搜索镜像。 安装步骤2&#xff1a;拉取镜像拉取镜像查看已拉取的镜像 安装步骤3&#xff1a;创建容器创建容器方式1&#xff1a;快速创建容器创…

leetcode810. 黑板异或游戏(博弈论 - java)

黑板异或游戏 lc 810 - 黑板异或游戏题目描述博弈论 动态规划 lc 810 - 黑板异或游戏 难度 - 困难 原题链接 - 黑板异或游戏 题目描述 黑板上写着一个非负整数数组 nums[i] 。 Alice 和 Bob 轮流从黑板上擦掉一个数字&#xff0c;Alice 先手。如果擦除一个数字后&#xff0c;剩…

我的创作纪念日(256天)

前言 结缘 我与csdn的结缘&#xff0c;之前在创作纪念日&#xff08;128天&#xff09;便已提到&#xff0c;今在此便不再多言 收获 很惭愧&#xff0c;自六月底至八月中旬&#xff0c;因为忙于找工作&#xff0c;奔赴面试求职之际&#xff0c;写博客没有像之前那么勤&#x…

【AI绘画】3分钟学会ikun幻术图

目录 前言一、效果展示二、准备工作三、操作步骤3.1平台创建实例3.2 启动SD 四、安装QR Code Monster 模型五、成图 前言 大家热爱的ikun幻术在今天的分享中将呈现。在本文中&#xff0c;我们将揭示一个备受欢迎的图像幻术技术&#xff0c;让您感受到令人惊叹的视觉创造力。 …

[管理与领导-23]:IT基层管理者 - 团队管理 - 新人来了,如何帮助新人快速进入角色?

目录 一、如何帮助新人快速进入角色 二、如何利用好试用期 一、如何帮助新人快速进入角色 1.1 案例1 以下是几个帮助新人快速进入角色的建议&#xff1a; 有组织安排入职会议&#xff1a;组织入职会议&#xff0c;让新人与团队所有成员互相介绍&#xff0c;并了解各自的工作…