Git Version

给一个commit(node),BFS输出所有commits (nodes)。followup :两个commits (nodes),找到他们的最近的公共parent,

思路: 就是先BFS一个,然后用map记录下其各个parent到这个commit(node)的距离,然后BFS第二个commit(node), 碰到在map里的node,就算一个总距离,然后更新最短距离和的点, 最后最短距离和的点就是结果了,写完面试官也表示很满意。这个注意解释下BFS的复杂度为什么是O(V+E),他会问为什么不是O(V)之类的。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;


public class GitVersion {
         public static List<Integer> findCommits1(GitNode root) { 
             List<Integer> result = new ArrayList<>();
             Set<GitNode> visited = new HashSet<>();
             Queue<GitNode> queue = new LinkedList<>(); 

             if (root == null) {
                 return result;
             }

             queue.offer(root);
             visited.add(root);              
             while (!queue.isEmpty()) {
                 GitNode curr = queue.poll();          
                 result.add(curr.val);                      
                 for (GitNode neighbor : curr.neighbors) {
                     if(!visited.contains(neighbor)){
                         queue.offer(neighbor);
                         visited.add(neighbor);
                     }
                 }

             }                 
             return result;             
         } 
    //back up for first step
          public List<Integer> findCommits(GitNode root) {  
                 List<Integer> result = new ArrayList<>();
                 Set<GitNode> visited = new HashSet<>();
                 Queue<GitNode> queue = new LinkedList<>();

                 findCommitsHelper(root, visited, queue, result);

                 return result;
             }

             private void findCommitsHelper(GitNode root, Set<GitNode> visited, 
                                            Queue<GitNode> queue, List<Integer> result) {
                 if (root == null) {
                     return;
                 }

                 queue.offer(root);

                 while (!queue.isEmpty()) {
                     GitNode curr = queue.poll();
                     if (!visited.contains(curr)) {
                         visited.add(curr);
                         result.add(curr.val);

                         for (GitNode neighbor : curr.neighbors) {
                             queue.offer(neighbor);
                         }
                     }
                 }
             }

             public int findLCA(GitNode node1, GitNode node2) {
                 if (node1 == null || node2 == null) {
                     throw new NullPointerException();
                 }

                 List<Integer> result1 = new ArrayList<>();
                 bfs(node1, result1);

                 List<Integer> result2 = new ArrayList<>();
                 bfs(node2, result2);

                 int i = result1.size() - 1;
                 int j = result2.size() - 1;


                 for (; i >= 0 && j >= 0; i--, j--) {
                     if (result1.get(i) == result2.get(j)) {
                         continue;
                     } else {
                         break;
                     }
                 }

                 return result1.get(i + 1 );
             }

             public int findLCALate(GitNode node1, GitNode node2) {
                 if (node1 == null || node2 == null) {
                     throw new NullPointerException();
                 }

                 List<Integer> result1 = new ArrayList<>();
                 bfs(node1, result1);

                  Set<GitNode> visited = new HashSet<>();
                 Queue<GitNode> queue = new LinkedList<>();

                 queue.offer(node2);

                 while (!queue.isEmpty()) {
                     GitNode curr = queue.poll();
                     if(result1.contains(curr.val)) return curr.val;
                     if (!visited.contains(curr)) {                 
                         visited.add(curr);                  
                         for (GitNode parent : curr.parents) {
                             queue.offer(parent);
                         }
                     }
                 }     

                 return 0;
             }      

             public int findLCAOffer(GitNode node1, GitNode node2) {
                 if (node1 == null || node2 == null) {
                     throw new NullPointerException();
                 }

                 List<Integer> result1 = new ArrayList<>();
                 Map<Integer, Integer> map = new HashMap<>();
                 bfs1(node1, result1, map);


                 Set<GitNode> visited = new HashSet<>();
                 Queue<GitNode> queue = new LinkedList<>();

                 queue.offer(node2);
                 visited.add(node2);
                 int count = 0;
                 int min = -1;
                 int res = Integer.MAX_VALUE;

                 while (!queue.isEmpty()) {
                         int size = queue.size();                        
                         for(int i = 0; i < size; i++){
                             GitNode curr = queue.poll();
                             if(result1.contains(curr.val)){                                
                                if(min == -1 || map.get(curr.val) + count < min){
                                     res = curr.val;
                                     min = map.get(curr.val) + count ;
                                 }
                             }

                            for (GitNode parent : curr.parents) {
                                if (!visited.contains(parent)) {
                                    queue.offer(parent);
                                    visited.add(parent);
                                }    
                            }

                         }
                         count++;
                     }

                 return res;
             }      


          private void bfs(GitNode root, List<Integer> result) {
                 if (root == null) {
                     return;
                 }

                 Set<GitNode> visited = new HashSet<>();
                 Queue<GitNode> queue = new LinkedList<>();

                 queue.offer(root);
                 visited.add(root);

                 while (!queue.isEmpty()) {
                     GitNode curr = queue.poll();
                     result.add(curr.val);
                     for (GitNode parent : curr.parents) {
                             if (!visited.contains(curr)) {
                                visited.add(curr);
                                queue.offer(parent);
                             }
                      }

                 }
             }

          private void bfs1(GitNode root, List<Integer> result, Map<Integer, Integer> map) {
                 if (root == null) {
                     return;
                 }

                 Set<GitNode> visited = new HashSet<>();
                 Queue<GitNode> queue = new LinkedList<>();

                 queue.offer(root);
                 visited.add(root);
                 int count = 0;

                 while (!queue.isEmpty()) {
                     int size = queue.size();
                     for(int i = 0; i < size; i++){
                         GitNode curr = queue.poll();
                         result.add(curr.val);
                         map.put(curr.val, count);

                        for (GitNode parent : curr.parents) {
                            if (!visited.contains(parent)) {
                                queue.offer(parent);
                                visited.add(parent);
                            }
                        }

                     }
                     count++;
                 }
             }

             public static void main(String[] args) {
              GitVersion sol = new GitVersion();
                 int[][] commits = new int[][]{{0, 1}, {0, 2},{1, 3}, {3, 5},  {2, 4}, {1, 4},{1,3},{3,7},{7,6},{6,4}};

                 GitNode node1 = null;
                 GitNode node2 = null;

                 // step 1: constrcut the graph
                 Map<Integer, GitNode> map = new HashMap<>();

                 for (int[] commit : commits) {
                     int from = commit[0];
                     int to = commit[1];

                     GitNode fromNode = null;
                     GitNode toNode = null;
                     if (map.containsKey(from)) {
                         fromNode = map.get(from);
                     } else {
                         fromNode = new GitNode(from);
                     }

                     if (map.containsKey(to)) {
                         toNode = map.get(to);
                         fromNode.neighbors.add(toNode);
                     } else {
                         toNode = new GitNode(to);
                         fromNode.neighbors.add(toNode);
                         map.put(to, toNode);
                     }

                     toNode.parents.add(fromNode);
                     map.put(from, fromNode);
                     map.put(to, toNode);
                 }

                 // Step 2: find out the root of the graph
                 GitNode root = null;
                 Map<GitNode, Integer> inDegree = new HashMap<>();
                 for (GitNode node : map.values()) {
                     if (!inDegree.containsKey(node)) {
                         inDegree.put(node, 0);
                     }

                     for (GitNode neighbor : node.neighbors) {
                         if (inDegree.containsKey(neighbor)) {
                             int degree = inDegree.get(neighbor);
                             inDegree.put(neighbor, degree + 1);
                         } else {
                             inDegree.put(neighbor, 1);
                         }
                     }
                 }

                 for (GitNode node : inDegree.keySet()) {
                     if (inDegree.get(node) == 0) {
                         root = node;
                         break;
                     }
                 }

                 System.out.println("Root is " + root.val);

                 node1 = map.get(4);
                 node2 = map.get(5);
                 List<Integer> result = sol.findCommits(root);
                 List<Integer> result2 = sol.findCommits1(root);
                 System.out.println(result);
                 System.out.println(result2);

                 int lca =1;
                 //int lca = sol.findLCA(node1, node2);

                // System.out.println("LCA is " + lca);

                 lca = sol.findLCAOffer(node1, node2);

                 System.out.println("LCA offer is " + lca);                 

                 lca = sol.findLCALate(node1, node2);

                 System.out.println("LCA late is " + lca);


                 for (Integer elem : result) {
                     System.out.println(elem);
                 }
             }

             static class GitNode {
                 int val;
                 List<GitNode> neighbors;
                 List<GitNode> parents;

                 public GitNode(int val) {
                     this.val = val;
                     this.neighbors = new ArrayList<>();
                     this.parents = new ArrayList<>();
                 }
             }

}

results matching ""

    No results matching ""