1. 程式人生 > 實用技巧 >1519. 子樹中標籤相同的節點數-無向圖、樹-中等難度

1519. 子樹中標籤相同的節點數-無向圖、樹-中等難度

問題描述

給你一棵樹(即,一個連通的無環無向圖),這棵樹由編號從 0 到 n - 1 的 n 個節點組成,且恰好有 n - 1 條 edges 。樹的根節點為節點 0 ,樹上的每一個節點都有一個標籤,也就是字串 labels 中的一個小寫字元(編號為 i 的 節點的標籤就是 labels[i] )

邊陣列 edges 以 edges[i] = [ai, bi] 的形式給出,該格式表示節點 ai 和 bi 之間存在一條邊。

返回一個大小為 n 的陣列,其中 ans[i] 表示第 i 個節點的子樹中與節點 i 標籤相同的節點數。

樹 T 中的子樹是由 T 中的某個節點及其所有後代節點組成的樹。

示例 1:

輸入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd"
輸出:[2,1,1,1,1,1,1]
解釋:節點 0 的標籤為 'a' ,以 'a' 為根節點的子樹中,節點 2 的標籤也是 'a' ,因此答案為 2 。注意樹中的每個節點都是這棵子樹的一部分。
節點 1 的標籤為 'b' ,節點 1 的子樹包含節點 1、4 和 5,但是節點 4、5 的標籤與節點 1 不同,故而答案為 1(即,該節點本身)。
示例 2:

輸入:n = 4, edges = [[0,1],[1,2],[0,3]], labels = "bbbb"

輸出:[4,2,1,1]
解釋:節點 2 的子樹中只有節點 2 ,所以答案為 1 。
節點 3 的子樹中只有節點 3 ,所以答案為 1 。
節點 1 的子樹中包含節點 1 和 2 ,標籤都是 'b' ,因此答案為 2 。
節點 0 的子樹中包含節點 0、1、2 和 3,標籤都是 'b',因此答案為 4 。
示例 3:

輸入:n = 5, edges = [[0,1],[0,2],[1,3],[0,4]], labels = "aabab"
輸出:[3,2,1,1,1]
示例 4:

輸入:n = 6, edges = [[0,1],[0,2],[1,3],[3,4],[4,5]], labels = "cbabaa"
輸出:[1,2,1,1,2,1]

示例 5:

輸入:n = 7, edges = [[0,1],[1,2],[2,3],[3,4],[4,5],[5,6]], labels = "aaabaaa"
輸出:[6,5,4,1,3,2,1]

提示:

1 <= n <= 10^5
edges.length == n - 1
edges[i].length == 2
0 <= ai,bi < n
ai !=bi
labels.length == n
labels 僅由小寫英文字母組成

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/number-of-nodes-in-the-sub-tree-with-the-same-label

解答

/*

只需要遍歷一遍樹,從根節點依次返回字母,在上層做累加。
把無向圖當做樹遍歷的時候,要注意父子節點的順序,可以用visited陣列來表示某個節點是否訪問過,先訪問的必然是根節點。

*/
class Solution {
    Map<Integer,List<Integer>> g;
    String labels;
    int[] result;
    public int[] dfs(int root, boolean[] visited){
        visited[root] = true;
        int[] count = new int[26];//26個字母
        count[labels.charAt(root) - 'a']++;
        for(int next:g.get(root)){
            if(!visited[next]){
                int[] res = dfs(next, visited);
                for(int i=0;i<26;i++)count[i]+=res[i];
            }
        }
        result[root] = count[labels.charAt(root) - 'a'];
        return count;
    }
    public int[] countSubTrees(int n, int[][] edges, String labels) {
        this.labels = labels;
        g = new HashMap<Integer,List<Integer>>();
        for(int i=0;i<n;i++)g.put(i,new ArrayList<Integer>());
        for(int[] temp:edges){
            g.get(temp[0]).add(temp[1]);
            g.get(temp[1]).add(temp[0]);
        }

        result = new int[n];
        boolean[] visited = new boolean[n];
        dfs(0, visited);
        return result;
    }
}
/*超時程式碼
class Solution {
    Map<Integer,List<Integer>> g;
    Map<Integer,Character> label;
    Map<Integer,Integer> count;
    List<Integer> visited;
    public int dfs(int start, char c){
        int num = 0;
        count.put(start,0);
        if(c == label.get(start))num = 1;
        for(int i:g.get(start)){
            if(!visited.contains(i) && count.get(i) == 1)num += dfs(i, c);
        }
        count.put(start,1);
        return num;
    }
    public int[] countSubTrees(int n, int[][] edges, String labels) {
        g = new HashMap<Integer,List<Integer>>();
        label = new HashMap<Integer,Character>();
        count = new HashMap<Integer,Integer>();
        if(n == 1){
            int[] res = {1};
            return res;
        }

        for(int i=0;i<n;i++){
            g.put(i,new ArrayList<Integer>());
            label.put(i,labels.charAt(i));
            count.put(i,1);
        }
        for(int[] temp:edges){
            g.get(temp[0]).add(temp[1]);
            g.get(temp[1]).add(temp[0]);
        }

        int[] res = new int[n];
        visited = new ArrayList<Integer>();
        List<Integer> todo = new ArrayList<Integer>();
        todo.add(0);

        while(!todo.isEmpty()){
            for(int i=0;i<todo.size();i++){
                visited.add(todo.get(i));
                res[todo.get(i)] = dfs(todo.get(i), label.get(todo.get(i)));
                for(int j:g.get(todo.get(i)))if(!visited.contains(j))todo.add(j);
                todo.remove(i);
            }
        }
        return res;
    }
}
*/