3331. 修改后子树的大小

简介: 【10月更文挑战第11天】3331. 修改后子树的大小

3331. 修改后子树的大小

找到距离节点x最近的祖先节点y,且s[x]==s[y]。然后将x连到y上.

题解

维护这个换父节点这个要求,所以需要从顶到下(只执行一次)dfs。同时维护路径上的每个字母对应的最新节点,初始化成一个全为-1的数组,表示(a-z)都是没有最新出现的。递归到x节点时,更新最新出现的位置,a[s[x]]=x

对于节点x及其子节点y如果a[s[y]]!=-1(说明前面s[y]这个字符一定出现过)。把y这个节点连到a[s[y]]这节点上,成为其子节点。同时把x的子节点y改成-1(说明已经把y移除了)。在第二次dfs(记录结果)中,不去递归等于-1的儿子。

注意写回溯递归返回前,要恢复a[s[x]]的原始值(递归到x之前的值)

第二次dfs

写一个自底向上的DFS,返回子树的大小。

当前子树大小为1(当前节点),加上所有子树的大小之和。

class Solution {
public:
    void f(string& s,vector<int>& a,vector<vector<int> >& dp,int x){
        int sx= s[x]-'a';
        int old = a[sx];//为之后回溯做准备
        a[sx]=x;//上一个祖先更新
        for(int i=dp[x].size()-1;i>=0;i--){//遍历子节点
            int y=dp[x][i];//子元素
            int tmp=a[s[y]-'a'];//找这个元素之前出现过没
            if(tmp!=-1){//如果之前出现过这个元素。
                dp[tmp].push_back(y);//将这个放在tmp上
                dp[x][i]=-1;// 删除y
            }
            f(s,a,dp,y);
        }
        a[sx]=old;
    }
    vector<int> findSubtreeSizes(vector<int>& parent, string s) {
        int n=parent.size();
        vector<vector<int> > dp(n);
        for(int i=1;i<n;i++){//第一个根节点为-1,不用管。
            dp[parent[i]].push_back(i);//记录子节点
        }
        vector<int> a(26,-1);
        // function<void(int)> f = [&](int x){
        //     int sx= s[x]-'a';
        //     int old = a[sx];//为之后回溯做准备
        //     a[sx]=x;//上一个祖先更新
        //     for(int i=dp[x].size()-1;i>=0;i--){//遍历子节点
        //         int y=dp[x][i];//子元素
        //         int tmp=a[s[y]-'a'];//找这个元素之前出现过没
        //         if(tmp!=-1){//如果之前出现过这个元素。
        //             dp[tmp].push_back(y);//将这个放在tmp上
        //             dp[x][i]=-1;// 删除y
        //         }
        //         f(y);
        //     }
        //     a[sx]=old;
        // };    
        f(s,a,dp,0);
        vector<int> ans(n,1);//注意这里把当前节点算进去
        auto dfs = [&](auto&& dfs,int x) -> void {
            for(int y: dp[x]){
                if(y!=-1){
                    dfs(dfs,y);
                    ans[x]+=ans[y];
                }
            }
        };
        dfs(dfs,0);
        return ans;
    }
};

也可以直接一次dfs自底向上,就是在维护的同时维护树的大小。

如果将y连到a[s[y]]上,就将其树大小加到a[s[y]]

如果y没有连到a[s[y]]上,那么说明它还连在原本节点x上,也就加到x上。

最后别忘了回溯

class Solution {
public:
    vector<int> findSubtreeSizes(vector<int>& parent, string s) {
        int n=parent.size();
        vector<vector<int> > dp(n);
        for(int i=1;i<n;i++){//第一个根节点为-1,不用管。
            dp[parent[i]].push_back(i);//记录子节点
        }
        vector<int> ans(n,1);//注意这里把当前节点算进去
        vector<int> a(26,-1);

        auto dfs = [&](auto&& dfs,int x) -> void {
            int sx= s[x]-'a';
            int old = a[sx];//为之后回溯做准备
            a[sx]=x;//上一个祖先更新
            for(int y: dp[x]){
                dfs(dfs,y);
                int tmp=a[s[y]-'a'];
                if(tmp==-1){//没出现过
                    ans[x]+=ans[y];//就是保持不动还连在原本的父节点上
                }else {
                    ans[tmp]+=ans[y];//换父节点
                }
            }
            a[sx]=old;
        };
        dfs(dfs,0);
        return ans;
    }
};
目录
相关文章
|
11月前
|
运维
【10月更文挑战赛】获奖名单出炉,快来看看谁是十月创作明星!
【10月更文挑战赛】获奖名单出炉,快来看看谁是十月创作明星!
315 9
|
11月前
|
运维 负载均衡 安全
|
12月前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
2608 44
|
11月前
|
安全 网络安全 数据安全/隐私保护
|
12月前
|
druid Java Maven
|
11月前
|
测试技术 API 开发工具
ElasticSearch7.6.x 模板及滚动索引创建及注意事项
ElasticSearch7.6.x 模板及滚动索引创建及注意事项
170 8
|
11月前
|
机器学习/深度学习 人工智能 监控
探索 AI 在软件开发中的新角色:代码审查与质量保证
【10月更文挑战第22天】本文探讨了AI在软件开发中的新角色,特别是在代码审查和质量保证方面。AI通过静态代码分析、代码风格一致性检查和历史数据学习,提高代码审查的效率和准确性。在质量保证中,AI还能够自动生成测试用例、监控应用性能并持续优化。文章还讨论了AI在软件开发中的实践应用、挑战与机遇,以及实施的最佳实践。
|
11月前
|
前端开发 JavaScript UED
CSS 中空格处理
【10月更文挑战第23天】正确处理 CSS 中的空格是实现良好页面布局和视觉效果的重要环节。通过了解空格的基本表现、对布局的影响以及各种处理方法,我们可以更好地掌握空格处理的技巧,为页面设计带来更精致、更专业的呈现。同时,要注意结合具体的项目需求和实际情况,灵活运用这些方法,以满足不同场景下的空格处理要求。
283 7
|
11月前
|
测试技术 API 开发工具
ElasticSearch的IK分词器
ElasticSearch的IK分词器
199 7
|
11月前
|
测试技术 API 开发工具
ElasticSearch核心概念:倒排索引
ElasticSearch核心概念:倒排索引
167 6