Question

For a undirected graph with tree characteristics, we can choose any node as the root. The result graph is then a rooted tree. Among all possible rooted trees, those with minimum height are called minimum height trees (MHTs). Given such a graph, write a function to find all the MHTs and return a list of their root labels.

Format The graph contains n nodes which are labeled from 0 to n - 1. You will be given the number n and a list of undirected edges (each edge is a pair of labels).

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

Example 1 :

Input: n = 4, edges = [[1, 0], [1, 2], [1, 3]]

        0
        |
        1
       / \
      2   3

Output: [1]

Example 2 :

Input: n = 6, edges = [[0, 3], [1, 3], [2, 3], [4, 3], [5, 4]]

     0  1  2
      \ | /
        3
        |
        4
        |
        5

Output: [3, 4]

Thinking:

  • Method 1: bfs, TLE
class Solution {
    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
        List<Integer> result = new ArrayList<>();
        if(n <= 0 || edges == null) return result;
        if(n == 1){
            result.add(0);
            return result;
        }
        Map<Integer, List<Integer>> map = new HashMap<>();
        for(int i = 0; i < n; i++)
            map.put(i, new ArrayList<Integer>());
        for(int[] arr: edges){
            map.get(arr[0]).add(arr[1]);
            map.get(arr[1]).add(arr[0]);
        }
        int min = Integer.MAX_VALUE;
        LABEL:
        for(int i = 0; i < n; i++){
            boolean[] visited = new boolean[n];
            List<Integer> list = map.get(i);
            LinkedList<Integer> queue = new LinkedList<>();
            queue.offer(i);
            int count = 0;
            while(!queue.isEmpty()){
                count++;
                if(count > min) continue LABEL;
                int size = queue.size();
                for(int j = 0; j < size; j++){
                    int cur = queue.poll();
                    if(visited[cur]) continue;
                    visited[cur] = true;
                    queue.addAll(map.get(cur));
                }
            }
            if(count == min)
                result.add(i);
            else if(count < min){
                min = count;
                result.clear();
                result.add(i);
            }
        }
        return result;
    }
}
  • Method 2: 类似拓扑
    • 先找到所有入度为1的,这些节点为叶子结点。
    • 不断从邻接表中删除对应的节点,直到最后剩下的结点,即为根节点。
class Solution {
    public List<Integer> findMinHeightTrees(int n, int[][] edges) {
        List<Integer> leaves = new ArrayList<>();
        if(n <= 0 || edges == null) return leaves;
        if(n == 1){
            leaves.add(0);
            return leaves;
        }
        List<Integer>[] map = new List[n];
        for(int i = 0; i < n; i++)
            map[i] = new ArrayList<Integer>();
        for(int[] arr: edges){
            map[arr[0]].add(arr[1]);
            map[arr[1]].add(arr[0]);
        }
        for(int i = 0; i < n; i++)
            if(map[i].size() == 1){
                leaves.add(i);
            }
        while(n > 2){
            n -= leaves.size();
            List<Integer> newLeaves = new ArrayList<>();
            for(int i : leaves){
                Integer cur = map[i].get(0);
                map[cur].remove(map[cur].indexOf(i));
                if(map[cur].size() == 1)
                    newLeaves.add(cur);
            }
            leaves = newLeaves;
        }
        return leaves;
    }
}

Second time

  1. BFS, AC, almost TLE
    class Solution {
     public List<Integer> findMinHeightTrees(int n, int[][] edges) {
         List<Integer>[] bag = new List[n];
         for(int i = 0; i < n; i++){
             bag[i] = new LinkedList<Integer>();
         }
         for(int[] pair : edges){
             bag[pair[0]].add(pair[1]);
             bag[pair[1]].add(pair[0]);
         }
         int min = Integer.MAX_VALUE;
         List<Integer> result = new LinkedList<>();
         for(int i = 0; i < n; i++){
             boolean[] visited = new boolean[n];
             LinkedList<Integer> queue = new LinkedList<>();
             queue.add(i);
             int count = 0;
             while(!queue.isEmpty()){
                 int size = queue.size();
                 for(int j = 0; j < size; j++){
                     Integer v = queue.poll();
                     visited[v] = true;
                     for(Integer node : bag[v]){
                         if(!visited[node]){
                             queue.add(node);
                         }
                     }
                 }
                 count++;
             }
             if(count == min) result.add(i);
             if(count < min){
                 result.clear();
                 result.add(i);
                 min = count;
             }
         }
         return result;
     }
    }
    
  2. Calculate the indegree of each node, if indegree is 1, add to queue.
    • once the remained node number is small or equal to 2, break the queue.
      class Solution {
       public List<Integer> findMinHeightTrees(int n, int[][] edges) {
        List<Integer> result = new LinkedList<>();
        if(n <= 2){
            for(int i = 0; i < n; i++) result.add(i);
            return result;
        }
        int[] count = new int[n];
        boolean[] visited = new boolean[n];
        List<Integer>[] bag = new List[n];
        for(int i = 0; i < n; i++) bag[i] = new LinkedList<>();
        for(int[] pair : edges){
            count[pair[0]]++;
            bag[pair[0]].add(pair[1]);
            count[pair[1]]++;
            bag[pair[1]].add(pair[0]);
        }
        LinkedList<Integer> queue = new LinkedList<>();
        int v = n;
        for(int i = 0; i < n; i++){
            if(count[i] == 1){
                queue.add(i);
                count[i]--;
            }
        }
        while(!queue.isEmpty() && v > 2){
            int size = queue.size();
            v -= size;
            for(int i = 0; i < size; i++){
                int val = queue.poll();
                visited[val] = true;
                List<Integer> list = bag[val];
                for(int node: list){
                    count[node]--;
                    if(count[node] == 1) queue.add(node);
                }
            }
        }
        for(int i = 0; i < n; i++){
            if(!visited[i]) result.add(i);
        }
        return result;
       }
      }