This approach utilizes a Depth First Search (DFS) to traverse each node of the tree. During traversal, we maintain a frequency array for each node to keep count of each label in its subtree. The recursion allows merging results from child nodes to calculate the current node's results.
The time complexity is O(n), where n is the number of nodes, because each node and edge is visited once during the DFS traversal. The space complexity is O(n), required for storing the graph representation and frequency arrays.
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5void dfs(int node, int parent, int** graph, int* graphSize, char* labels, int* result, int** countArr) {
6 int labelIndex = labels[node] - 'a';
7 countArr[node][labelIndex] = 1;
8 for (int i = 0; i < graphSize[node]; i++) {
9 int child = graph[node][i];
10 if (child == parent) continue;
11 dfs(child, node, graph, graphSize, labels, result, countArr);
12 for (int j = 0; j < 26; j++) {
13 countArr[node][j] += countArr[child][j];
14 }
15 }
16 result[node] = countArr[node][labelIndex];
17}
18
19int* countSubTrees(int n, int** edges, int edgesSize, int* edgesColSize, char* labels, int* returnSize) {
20 int** graph = (int**)malloc(n * sizeof(int*));
21 int* graphSize = (int*)calloc(n, sizeof(int));
22 for (int i = 0; i < n; i++) {
23 graph[i] = (int*)malloc(n * sizeof(int));
24 }
25 for (int i = 0; i < edgesSize; i++) {
26 int a = edges[i][0];
27 int b = edges[i][1];
28 graph[a][graphSize[a]++] = b;
29 graph[b][graphSize[b]++] = a;
30 }
31
32 int** countArr = (int**)malloc(n * sizeof(int*));
33 for (int i = 0; i < n; i++) {
34 countArr[i] = (int*)calloc(26, sizeof(int));
35 }
36
37 int* result = (int*)calloc(n, sizeof(int));
38 dfs(0, -1, graph, graphSize, labels, result, countArr);
39
40 *returnSize = n;
41 for (int i = 0; i < n; i++) {
42 free(graph[i]);
43 free(countArr[i]);
44 }
45 free(graph);
46 free(countArr);
47 free(graphSize);
48 return result;
49}
The solution follows a DFS approach to traverse the tree. We initialize an adjacency list for the graph representation. A frequency array is maintained for each node to count the occurrence of each character in the node's subtree. During the DFS traversal, we update the frequency array for the current node using the frequency arrays of its children. Finally, we set the result for the current node as the count of its own label within its subtree.
This alternative approach utilizes a HashMap to dynamically manage counts of node labels as opposed to fixed-size arrays. The hash map structure allows potential extension to accommodate varying character sets, though for this problem, it's implemented for the fixed set of labels 'a' to 'z'.
The solution has a time complexity of O(n) given tree node analysis occurs once each during DFS with label counting operations. Space complexity is O(n), due to memory allocations for the graph and storage structures.
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5typedef struct {
6 int *counts;
7 int size;
8} CountMap;
9
10CountMap* createCountMap() {
11 CountMap* countMap = (CountMap*)malloc(sizeof(CountMap));
12 countMap->counts = (int*)calloc(26, sizeof(int));
13 countMap->size = 26;
14 return countMap;
15}
16
17void freeCountMap(CountMap* countMap) {
18 free(countMap->counts);
19 free(countMap);
20}
21
22void mergeMaps(CountMap* target, CountMap* source) {
23 for (int i = 0; i < source->size; i++) {
24 target->counts[i] += source->counts[i];
25 }
26}
27
28void dfs(int node, int parent, int** graph, int* graphSize, char* labels, int* result, CountMap** countMaps) {
29 int labelIndex = labels[node] - 'a';
30 countMaps[node]->counts[labelIndex] = 1;
31
32 for (int i = 0; i < graphSize[node]; i++) {
33 int child = graph[node][i];
34 if (child == parent) continue;
35 dfs(child, node, graph, graphSize, labels, result, countMaps);
36 mergeMaps(countMaps[node], countMaps[child]);
37 }
38
39 result[node] = countMaps[node]->counts[labelIndex];
40}
41
42int* countSubTrees(int n, int** edges, int edgesSize, int* edgesColSize, char* labels, int* returnSize) {
43 int** graph = (int**)malloc(n * sizeof(int*));
44 int* graphSize = (int*)calloc(n, sizeof(int));
45 for (int i = 0; i < n; i++) {
46 graph[i] = (int*)malloc(n * sizeof(int));
47 }
48 for (int i = 0; i < edgesSize; i++) {
49 int a = edges[i][0];
50 int b = edges[i][1];
51 graph[a][graphSize[a]++] = b;
52 graph[b][graphSize[b]++] = a;
53 }
54
55 CountMap** countMaps = (CountMap**)malloc(n * sizeof(CountMap*));
56 for (int i = 0; i < n; i++) {
57 countMaps[i] = createCountMap();
58 }
59
60 int* result = (int*)calloc(n, sizeof(int));
61 dfs(0, -1, graph, graphSize, labels, result, countMaps);
62
63 *returnSize = n;
64 for (int i = 0; i < n; i++) {
65 free(graph[i]);
66 freeCountMap(countMaps[i]);
67 }
68 free(graph);
69 free(countMaps);
70 free(graphSize);
71 return result;
72}
This C solution replaces the fixed array used for counting character occurrences with dynamically sized CountMap structures, implementing a merge function to combine results from child nodes into their parent node's structure during DFS. Each node manages its own label counts, which are summed in the result array.