题解 | #小米Git#

小米Git

https://www.nowcoder.com/practice/4fcd94851d9142458329fd1d3e5802a8

1.先对数据进行预处理,生成邻接表 2.再对图(也可以理解成多叉树,但是没有方向)进行层序遍历,拿到自定向下的结点顺序 3.外层负责确定接下来作为根结点处理的结点,内层负责对根节点直接关联的子节点构成的子树进行目标查找。 注意:存在情况,子树同时包含两个目标,这时候公共根结点应该为子树的某个结点,而非root。因此需要引入tmpfindA和tmpfindB,它们是判断与root直接关联的子结点构成的子树中是否包含目标的依据;findA和findB是判断root能否成为公共结点的依据。

import java.util.*;

public class Solution {
    public static int findA;
    public static int findB;
    public static ArrayList<Integer> visitedNode;//辅助构建有向图
    public int Git (String[] matrix, int versionA, int versionB) {
        //1.将字符数组转换成邻接表
        int[][] arr = new int[matrix.length][matrix[0].length()];
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length(); j++) {
                arr[i][j] = matrix[i].charAt(j) - '0';
            }
        }
      
        //2.层序遍历,存储自顶向下自左向右顺序的结点集合。作用是,为下面每个结点作为根结点进行处理提供顺序。确保了上层结点优先作为根节点进行处理。
        ArrayList<Integer> list = new ArrayList<>();
        layOrder(arr,list);
      
        //用于存储处理完毕的根节点
        visitedNode = new ArrayList<>();
      
      	//3.将邻接表中每一个结点作为根节点进行一次处理,判断是否能够成为公共结点。
        for(int i=0;i<list.size();i++){
            visitedNode.add(list.get(i));//存入集合,表示已作为根节点进行访问
            //-1表示未找到目标,这两个变量主要为当前结点作为根的子树服务。提供root是否能够成为公共结点的依据。
            findA = -1;
            findB = -1;
            int root = list.get(i);//i表示当前root在list中的下标
            if(root == versionA || root == versionB){
                return root;//作为根节点,root已经匹配某个目标,那么另一个目标必然存在于以root为根的多叉树中,root必然是公共结点。
            }
            //处理root直接关联的子结点
            for(int j=0;j<arr[root].length;j++){
                //记录当前直接关联的子节点构成的子树经过dfs后的结果
                int tmpfindA = findA;
                int tmpfindB = findB;
                if(arr[root][j] == 1){
                    dfs(arr,j,versionA,versionB,new boolean[arr.length]);
                }
              	//两个临时变量都发生了改变,说明这棵子节点构成的子树包含两个目标,而root不是公共父节点。因此需要重置findA、B,避免误判root为公共节点
                if(tmpfindA != findA && tmpfindB != findB){
                    findA = -1;
                    findB = -1;//重置等待下次这个子节点j作为root时再处理
                }
            }
          	//两个变量都发生了改变,说明两个目标分别在root的两棵子树
            if(findA != -1 && findB != -1){
                return root;
            }
          	//只有一个发生改变,说明两个部门在同一条枝上,因此先发现的目标的那个位置即公共节点。可能是A先被发现,也可能是B先被发现。
            if(findA != -1){
                return findA;
            }
            if(findB != -1){
                return findB;
            }
        }
        return 0;
    }
  	//搜索是否存在目标,只要搜索到一个目标,当前分支后面的搜索将不再进行。
    public static void dfs(int[][] arr, int curNode, int versionA, int versionB,
                           boolean[] visited) {
        visited[curNode] = true;
        if (curNode == versionA) {
            findA = curNode;
            return;
        }
        if (curNode == versionB) {
            findB = curNode;
            return;
        }
        for(int i=0;i<arr[curNode].length;i++){
            //visitedNode作用是防止向上dfs
            if(visited[i] == false && !visitedNode.contains(i) && i != curNode && arr[curNode][i] == 1){
                dfs(arr,i,versionA,versionB,visited);
            }
        }
    }
  	//层序遍历
    public static void layOrder(int[][] arr,ArrayList<Integer> list){
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(0);
        list.add(0);
        while(!queue.isEmpty()){
            int size = queue.size();
            for(int i=0;i<size;i++){
                int node = queue.poll();
                for(int j=0;j<arr[node].length;j++){
                    if(arr[node][j] == 1 && !list.contains(j)){
                        queue.offer(j);
                        list.add(j);
                    }
                }
            }
        }
    }
}
#我的实习求职记录##23届找工作求助阵地#
全部评论

相关推荐

点赞 评论 收藏
分享
05-30 12:03
山西大学 C++
offer来了我跪着接:不是骗子,等到测评那一步就知道为啥这么高工资了
点赞 评论 收藏
分享
鼠鼠没有找到暑期实习,简历太空了,感觉直接去秋招会完蛋,这个时间点找个日常实习混个简历,边实习边准备秋招有没有搞头啊
梦想是成为七海千秋:可以的完全可以的,找不到暑期就找日常,秋招之前还是有很多时间可以实习的,哪怕只实习了一个月都可以写在简历上
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务