Day~3: 小米Git

237 阅读3分钟

描述

Git 是一个常用的分布式代码管理工具,Git 通过树的形式记录文件的更改历史(例如示例图),树上的每个节点表示一个版本分支,工程师经常需要找到两个分支的最近的分割点。

例如示例图中 3,4 版本的分割点是 1。3,5 版本的分割点是 0。

给定一个用邻接矩阵 matrix 表示的树,请你找到版本 versionA 和 versionB 最近的分割点并返回编号。

注意:

1.矩阵中从第一行 (视为节点 0 )开始,表示与其他每个点的连接情况,例如 [01011,10100,01000,10000,10000] 表示节点 0 与节点 1 , 3 , 4相连,节点 1 与节点 0 , 2相连,其他点的以此类推。

2.并不保证是一棵二叉树,即一个节点有可能有多个后继节点,我们把节点 0 视为树的根节点。

数据范围:树上节点数量满足 1 ≤ n ≤ 100

示例图

示例1

输入:["01011","10100","01000","10000","10000"],1,2
返回值:1

示例2

输入:["0"],0,0
返回值:0

算法思路

将邻接矩阵转换为父子关系矩阵,通过一个flags数组判断父节点是否被访问过,如果两个开始求的节点往上求父节点的过程中有重复的节点,这个节点即为分割点,比如上图中的3和5,3的往上求父节点过程为3->1->0,5的往上求父节点的过程为5->2->0,两个路径在0处重叠,0即为3和5的分割点。

邻接矩阵转父子关系矩阵的过程如下所示:
如邻接矩阵
0 1 0 1 1
1 0 1 0 0
0 1 0 0 0
1 0 0 0 0
1 0 0 0 0
转换为父子关系矩阵为
0 1 0 1 1
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
其中这个矩阵matrix[i][j]表示节点i和节点j相接
转换过程为从第一行开始找值为1的点,第一行为头结点,只有子节点,所以如果matrix[0][i] == 1,那就将matrix[i][0]处的值设置为0,然后判断第i行的子节点,相当于深度遍历,最终矩阵中只剩下每行代表的节点的子节点的位置(即列号),以上面父子关系矩阵为例,要找2的父节点,则依次判断matrix[i][2] == 1,如果相等,则节点i就是节点2的父节点,这里matrix[1][2] == 1,所以节点1是节点2的父节点。

判断节点是否被访问过可以使用一个一维数组flags来记录,当寻找到节点i时,就将i设置为true(默认为false),当发现当前节点已经被访问过,则返回当前节点,即所求分割点

代码实现

public void setDirected(int[][] matrix, int r) {
        for (int i = 0; i < matrix.length; i++) {
            if (matrix[r][i] == 1) {
                matrix[i][r] = 0;
                setDirected(matrix, i);
            }
        }
    }
    
    public int setFlags(int[][] m, boolean[] flags, int version, int row) {
        while (version != 0) {
            if (flags[version] == true) {
                return version;
            } else {
                flags[version] = true;
            }
            for (int i = 0; i < row; i++) {
                if (m[i][version] == 1) {
                    if (flags[i] == true) {
                        return i;
                    }
                    if (i == 0) {
                        flags[i] = true;
                    }
                    version = i;
                    break;
                }
            }
        }
        return 0;
    }
    
    public int Git (String[] matrix, int versionA, int versionB) {
        if (versionA == versionB) {
            return versionA;
        }
        
        int row = matrix.length;
        int column = matrix[0].length();
        int[][] m = new int[row][column];
        
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                m[i][j] = Integer.parseInt(matrix[i].substring(j, j+1));
            }
        }
        
        setDirected(m, 0);
        
        boolean[] flags = new boolean[row];
        
        setFlags(m, flags, versionA, row);
        int res = setFlags(m, flags, versionB, row);
        
        return res;
    }

参考

elimuzi的博客文章:算法: 小米Git