首页 > 编程语言 >最近公共祖先-算法学习

最近公共祖先-算法学习

时间:2023-06-21 22:31:33浏览次数:46  
标签:祖先 cache 第个 depth int 算法 公共 节点

问题提出

  • 如何计算树上任意两点 xy 的最近公共祖先 呢?
  • 通俗地理解-假设在一棵二叉树中,有两个节点 最近公共祖先-算法学习_取整最近公共祖先-算法学习_取整_02
  • 那么该如何求这两个节点的最近公共祖先节点最近公共祖先-算法学习_最近公共祖先_03
  • 如下图,节点 最近公共祖先-算法学习_最近公共祖先_04和节点最近公共祖先-算法学习_取整_05的最近公共祖先节点是最近公共祖先-算法学习_最近公共祖先_03

最近公共祖先-算法学习_List_07

思路解析

  1. 假设一个节点的深度为,这可以通过一次 DFS 预处理出来。
  1. 那么这里如何进行预处理呢?
  2. 单纯找一个节点最近公共祖先-算法学习_取整_08的深度的解决办法较为简单
  1. 假设最近公共祖先-算法学习_最近公共祖先_09(否则交换两个节点的位置)
  2. 可以先把更靠下的更新为第个祖先节点,这样和就处于同一深度了
  1. 这一句话还不理解,然后怎么理解呢?
  2. 如图 图-Tree1 节点最近公共祖先-算法学习_取整_10的深度是最近公共祖先-算法学习_取整_05,节点最近公共祖先-算法学习_取整_12的深度是最近公共祖先-算法学习_List_13
  3. 那么就把更靠下的最近公共祖先-算法学习_取整_12更新为其第最近公共祖先-算法学习_最近公共祖先_15个祖先节点节点,也就是节点最近公共祖先-算法学习_List_16
  1. 如果此时,那么就是
  1. 这里意思是如果节点最近公共祖先-算法学习_取整_02更新之后等于节点最近公共祖先-算法学习_取整那么这两个节点的公共节点就是最近公共祖先-算法学习_取整
  2. 否则说明最近公共祖先-算法学习_最近公共祖先_03在更上面,那么就把最近公共祖先-算法学习_取整最近公共祖先-算法学习_取整_02一起往上跳
  1. 由于不知道最近公共祖先-算法学习_最近公共祖先_03的具体位置,只能不断尝试,先尝试大步跳,再尝试小步跳。
  2. 最近公共祖先-算法学习_最近公共祖先_24(表示对 以 2 为底 n 的对数进行向下取整),循环直到 最近公共祖先-算法学习_最近公共祖先_25
  3. 每次循环逻辑如下
  1. 如果最近公共祖先-算法学习_取整的第最近公共祖先-算法学习_最近公共祖先_27个祖先节点不存在,即最近公共祖先-算法学习_List_28,说明步子迈大了,将最近公共祖先-算法学习_取整_08减 1,继续循环
  2. 如果的第个祖先节点存在,且。说明在的上面
  1. 那么更新最近公共祖先-算法学习_List_30,将最近公共祖先-算法学习_取整_08最近公共祖先-算法学习_最近公共祖先_04然后继续循环
  1. 最近公共祖先-算法学习_List_33,那么最近公共祖先-算法学习_最近公共祖先_03可能在最近公共祖先-算法学习_取整_35的下面,由于无法向下跳,只能将最近公共祖先-算法学习_取整_08最近公共祖先-算法学习_最近公共祖先_04,然后继续循环
  1. 循环结束的时候,与只有一步之遥,即
  1. 是如何得出该结论的?

  • 以寻找节点最近公共祖先-算法学习_List_38和节点最近公共祖先-算法学习_List_39的最近公共祖先节点为例

最近公共祖先-算法学习_最近公共祖先_40

  • 那么首先更新更深的节点最近公共祖先-算法学习_List_38最近公共祖先-算法学习_取整_42从而保证了和节点最近公共祖先-算法学习_List_39位于相同的深度

最近公共祖先-算法学习_最近公共祖先_44

然后开始向上寻找,这里假设树或者图一共有最近公共祖先-算法学习_取整_45个节点,那么极端情况下,最底层的节点的第最近公共祖先-算法学习_取整_46个祖先节点是根节点

又因为一个正整数可以写成若干个 2 次幂数的和,即寻找一个节点的祖先节点的时候,可以依次寻找其第最近公共祖先-算法学习_最近公共祖先_27个祖先节点

ex:最近公共祖先-算法学习_List_48,即寻找一个节点的第13个祖先节点,可以依次寻找第最近公共祖先-算法学习_List_49个祖先节点即可。

  • 所以这里有 最近公共祖先-算法学习_最近公共祖先_24,向下取整是因为节点本身需要被忽略
  • 以图示为例,这里可以计算得出最近公共祖先-算法学习_最近公共祖先_51
  • 这里设
  • 那么很显然最开始最近公共祖先-算法学习_取整的第最近公共祖先-算法学习_List_53个祖先节点不存在
  • 最近公共祖先-算法学习_最近公共祖先_54,第最近公共祖先-算法学习_List_55个祖先节点也不存在,继续 最近公共祖先-算法学习_取整_56
  • 直到最近公共祖先-算法学习_取整_57,则最近公共祖先-算法学习_取整的第最近公共祖先-算法学习_List_59个祖先节点是节点最近公共祖先-算法学习_取整_05
  • 那么此时对于最近公共祖先-算法学习_最近公共祖先_61而言,其第最近公共祖先-算法学习_List_13个祖先节点相同。但是暂时不确定是不是最近的公共祖先节点
  • 所以 继续 最近公共祖先-算法学习_取整_63,此时需要找到节点最近公共祖先-算法学习_最近公共祖先_61的第最近公共祖先-算法学习_List_65个公共节点分别是最近公共祖先-算法学习_取整_66
  • 此时满足最近公共祖先-算法学习_最近公共祖先_67,则更新最近公共祖先-算法学习_最近公共祖先_68,然后更新最近公共祖先-算法学习_List_69
  • 此时寻找最近公共祖先-算法学习_最近公共祖先_61的第最近公共祖先-算法学习_List_71个祖先节点分别是最近公共祖先-算法学习_List_72,然后更新最近公共祖先-算法学习_List_73
  • 此时退出循环。则最近公共祖先节点--

思路总结

  1. 总的来说,寻找祖先节点,需要使用二维数组来缓存节点的祖先节点。
  2. 然后利用最近公共祖先-算法学习_最近公共祖先_74方法来寻找公共组建节点,降低查找次数

代码实现

  • 通常入参是 二维最近公共祖先-算法学习_最近公共祖先_75数组的形式,然后利用最近公共祖先-算法学习_最近公共祖先_75来建图
class TreeAncestor {

    // 缓存公共祖先节点
    private int[][] cache;
    private int[] depth;

    public TreeAncestor(int[][] edges) {
        int n = edges.length - 1;
        int m = 32 - Integer.numberOfLeadingZeros(n);
        // 使用 List 数组表示 邻接表
        List<Integer> g[] = new ArrayList[];
        // 初始化数组元素
        Arrays.setAll(g, e -> new ArrayList<>());
        // 遍历节点
        for(int[] edge : edges) {
            int x = e[0], y = e[1];
            g[x].add(y);
            g[y].add(x);
        }
        depth = new int[n];
        cache = new int[n][m];
        
        dfs(g, 0, -1);

        for (int i = 0; i < m - 1; i++) {
            for (int x = 0; x < n; x++) {
                int p = cache[x][i];
                cache[x][i + 1] = p < 0 ? -1 : pa[p][i];
            }
        }
    }

    private void dfs(List<Integer>[] g, int x, int fa) {
        cache[x][0] = fa;
        for (int y : g[x]) {
            if (y != fa) {
                depth[y] = depth[x] + 1;
                dfs(g, y, x);
            }
        }
    }

    public int getKthAncestor(int node, int k) {
        for (; k > 0; k &= k - 1)
            node = cache[node][Integer.numberOfTrailingZeros(k)];
        return node;
    }

    public int getLCA(int x, int y) {
        if (depth[x] > depth[y]) {
            int tmp = y;
            y = x;
            x = tmp;
        }
        // 使 y 和 x 在同一深度
        y = getKthAncestor(y, depth[y] - depth[x]);
        if (y == x)
            return x;
        for (int i = cache[x].length - 1; i >= 0; i--) {
            int px = cache[x][i], py = pa[y][i];
            if (px != py) {
                x = px;
                y = py;
            }
        }
        return cache[x][0];
    }

    
}

参考

https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/solution/mo-ban-jiang-jie-shu-shang-bei-zeng-suan-v3rw/

标签:祖先,cache,第个,depth,int,算法,公共,节点
From: https://blog.51cto.com/u_16079703/6532444

相关文章

  • 代码随想录算法训练营第43天 | ● 1049. 最后一块石头的重量 II ● 494. 目标和
     第九章 动态规划 part05●  1049. 最后一块石头的重量 II ●  494. 目标和 ●  474.一和零    详细布置   1049. 最后一块石头的重量 II  本题就和 昨天的 416. 分割等和子集 很像了,可以尝试先自己思考做一做。 视频讲解:https://www......
  • 基于粒子群算法的电力系统最优潮流 以IEEE30节点的六机为对象,建立考虑功率平衡、机组
    基于粒子群算法的电力系统最优潮流 以IEEE30节点的六机为对象,建立考虑功率平衡、机组爬坡约束、出力限制约束的电力系统经济调度模型,采用粒子群算法对模型进行求解,得到六个机组的最优运行计划,确定系统最优运行成本。这段程序主要是一个基于粒子群优化算法(PSO)的电力系统调度程序......
  • 含分布式电源的基于粒子群算法的配电网重构算法:改进粒子群算法 优化目标:有功网损最
    含分布式电源的基于粒子群算法的配电网重构算法:改进粒子群算法优化目标:有功网损最小潮流计算模型:前推回代法计算模型采用IEEE33节点标准模型输出结果如”下图片所示.文件含:MATLAB程序、Visio模型图和程序框图、输出结果图、参考文献。这个程序主要是一个粒子群算法,用于解......
  • 数据挖掘中的机器学习算法研究
    目录数据挖掘中的机器学习算法研究是人工智能领域中的重要方向之一。机器学习是指通过计算机算法,让计算机从数据中自动提取规律和特征,从而实现对数据的分析和决策。在数据挖掘中,机器学习算法起着至关重要的作用,能够实现对大量数据的自动学习和分析,为实际应用提供重要的支持。本文......
  • 完美解决方案-雪花算法ID到前端之后精度丢失问题
    packagecom.wl.dep_vue.config;importcom.fasterxml.jackson.databind.ObjectMapper;importcom.fasterxml.jackson.databind.module.SimpleModule;importcom.fasterxml.jackson.databind.ser.std.ToStringSerializer;importorg.springframework.boot.autoconfigure.......
  • matlab的基于遗传算法优化bp神经网络多输入多输出预测模型
    matlab的基于遗传算法优化bp神经网络多输入多输出预测模型,有代码和EXCEL数据参考,精度还可以,直接运行即可,换数据OK。原创文章,转载请说明出处,资料来源:http://imgcs.cn/5c/632809753171.html这个程序是一个基于遗传算法优化的BP神经网络多输入两输出模型。下面我将对程序进行详细分析......
  • 基于粒子群的PMU优化配置,是一个使用粒子群优化算法(Particle Swarm Optimization, PSO
    基于粒子群的PMU优化配置软件:MATLAB介绍:电力系统PMU优化配置,为了使电力系统达到完全可观,以PMU配置数量最少为目标函数,运用粒子群算法进行优化处理,在IEEE303957118系统进行仿真验证。这段代码是一个使用粒子群优化算法(ParticleSwarmOptimization,PSO)来解决IEEE39节点电力......
  • [Leetcode] 0014. 最长公共前缀
    14.最长公共前缀点击上方,跳转至Leetcode题目描述编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。 示例1:输入:strs=["flower","flow","flight"]输出:"fl"示例2:输入:strs=["dog","racecar","car"]输出......
  • 算法与数据结构Day04——寻找大富翁
    #include<bits/stdc++.h>usingnamespacestd;intmain(){intN,M;priority_queue<int,vector<int>,less<int>>q;cin>>N>>M;for(inti=0;i<N;i++){inttemp;cin>>tem......
  • Android Bresenham 直线算法 让你的手势更丝滑
    Bresenham算法是一种用于绘制直线的算法,它通过在离散的像素点上进行逐步的迭代来绘制出近似直线。以下是一个示例代码,演示了如何使用Bresenham算法绘制直线:fundrawLine(x0:Int,y0:Int,x1:Int,y1:Int){valdx=Math.abs(x1-x0)valdy=Math.abs(y1-......