
2025-05-20:修改后子树的大小。用go语言,给你一棵有 n 个节点的树,节点编号从 0 到 n-1,且节点 0 是树的根。树的结构用一个长度为 n 的数组 parent 表示,其中 parent[i] 表示节点 i 的父节点编号。由于节点 0 是根节点,所以 parent[0] = -1。
同时给你一个长度为 n 的字符串 s,s[i] 表示节点 i 对应的字符。
对每个编号为 1 到 n-1 的节点 x,执行如下操作一次:
执行完这些操作后,返回一个长度为 n 的数组 answer,其中 answer[i] 表示最终树中,以节点 i 为根的子树包含的节点个数。
n == parent.length == s.length。
1 <= n <= 100000。
对于所有的 i >= 1 ,都有 0 <= parent[i] <= n - 1 。
parent[0] == -1。
parent 表示一棵合法的树。
s 只包含小写英文字母。
输入:parent = [-1,0,0,1,1,1], s = "abaabc"。
输出:[6,3,1,1,1,1]。
解释:

在这里插入图片描述
节点 3 的父节点从节点 1 变为节点 0 。
题目来自力扣3331。
我们有一棵树,节点编号从0到n-1,其中0是根节点。树的连接关系由parent数组给出,parent[i]表示节点i的父节点。同时,每个节点有一个对应的字符s[i]。我们需要对每个非根节点(即节点1到n-1)执行一次操作:
s[x] == s[y]。parent[x]改为y。执行完所有操作后,我们需要计算每个节点作为根的子树的大小(即子树中包含的节点数量)。
我们需要对节点1到5分别执行操作:
1. 节点1:
2. 节点2:
3. 节点3:
0 (a)
/ | \
1(b)2(a)3(a)
/ \
4(b)5(c)4. 节点4:
5. 节点5:
最终树的结构:
0 (a)
/ | \
1(b)2(a)3(a)
/ \
4(b)5(c)现在我们需要计算每个节点作为根的子树的大小:
因此,answer = [6, 3, 1, 1, 1, 1]。
代码的主要逻辑是通过深度优先搜索(DFS)来计算子树大小。具体步骤如下:
parent数组构建邻接表g,表示每个节点的子节点。size数组,表示每个节点的子树大小。ancestor数组(长度为26,对应小写字母),记录当前路径中每个字符最近的祖先节点。x:size[x] = 1(至少包含自己)。s[x]的旧祖先,并将ancestor[s[x]]更新为x。y:y,找到其字符s[y]的最近祖先anc(如果ancestor[s[y]]为-1,则用x作为默认祖先)。size[anc]增加size[y](因为y的子树现在属于anc的子树)。ancestor[s[x]]为旧值(回溯)。size数组即为所求的answer。ancestor数组的操作是O(1)(因为字母表是固定大小的26)。g:O(n)。size数组:O(n)。ancestor数组:O(26) = O(1)。size数组即为答案。package main
import (
"fmt"
)
func findSubtreeSizes(parent []int, s string) []int {
n := len(parent)
g := make([][]int, n)
for i := 1; i < n; i++ {
p := parent[i]
g[p] = append(g[p], i)
}
size := make([]int, n)
ancestor := [26]int{}
for i := range ancestor {
ancestor[i] = -1
}
var dfs func(int)
dfs = func(x int) {
size[x] = 1
sx := s[x] - 'a'
old := ancestor[sx]
ancestor[sx] = x
for _, y := range g[x] {
dfs(y)
anc := ancestor[s[y]-'a']
if anc < 0 {
anc = x
}
size[anc] += size[y]
}
ancestor[sx] = old // 恢复现场
}
dfs(0)
return size
}
func main() {
parent := []int{-1, 0, 0, 1, 1, 1}
s := "abaabc"
result := findSubtreeSizes(parent, s)
fmt.Println(result)
}

fn find_subtree_sizes(parent: Vec<i32>, s: &str) ->Vec<i32> {
letn = parent.len();
letmut g = vec![vec![]; n];
foriin1..n {
letp = parent[i] asusize;
g[p].push(i);
}
letmut size = vec![0; n];
// 记录字符对应最近祖先节点编号,-1 表示无
letmut ancestor = vec![-1; 26];
lets_bytes = s.as_bytes();
fndfs(
x: usize,
g: &Vec<Vec<usize>>,
s_bytes: &[u8],
ancestor: &mutVec<i32>,
size: &mutVec<i32>,
) {
size[x] = 1;
letsx = (s_bytes[x] - b'a') asusize;
letold = ancestor[sx];
ancestor[sx] = x asi32;
for &y in &g[x] {
dfs(y, g, s_bytes, ancestor, size);
letanc = ancestor[(s_bytes[y] - b'a') asusize];
letanc_index = if anc < 0 { x asi32 } else { anc };
size[anc_index asusize] += size[y];
}
ancestor[sx] = old; // 恢复现场
}
dfs(0, &g, s_bytes, &mut ancestor, &mut size);
size
}
fnmain() {
letparent = vec![-1, 0, 0, 1, 1, 1];
lets = "abaabc";
letresult = find_subtree_sizes(parent, s);
println!("{:?}", result);
}