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;
    }
};
目录
相关文章
|
分布式计算 Java 数据处理
Flink - TimeWindow And TimeWindowAll 详解
Flink 流处理用于处理源源不断的数据,之前介绍过 processFunction,该方法会对单个元素进行处理,除此之外,还有一种批量数据处理的方法就是 TimeWindow 以及 TimeWindowAll,Flink 时间窗口可以看作是对无线数据流设置的有限数据集。...
1415 0
Flink - TimeWindow And TimeWindowAll 详解
|
前端开发 算法 Unix
面向前端设计的DFT基础介绍(一)——MBIST存储器内建自测试
本文介绍了MBIST存储器内建自测试的中,MBIST的特点,如何测试,Tessent加入的测试逻辑的结构等基础知识,继而以几个实例的图示和解读,描述了RTL设计满足MBIST设计的前置需求。
44203 3
面向前端设计的DFT基础介绍(一)——MBIST存储器内建自测试
|
12月前
|
运维
【10月更文挑战赛】获奖名单出炉,快来看看谁是十月创作明星!
【10月更文挑战赛】获奖名单出炉,快来看看谁是十月创作明星!
347 9
|
druid Java Maven
|
数据采集 监控 算法
原子钟的基本介绍
【10月更文挑战第7天】本文介绍原子钟是一种利用原子跃迁频率作为基准的高精度计时设备,广泛应用于通信、导航、科学研究等领域。铯原子钟是最精确的计时设备之一,基于铯133原子的超精细跃迁,频率为9,192,631,770 Hz。其关键部件包括铯束源、微波腔、磁态选择器、检测系统和反馈回路。原子钟在GPS、电信、金融市场等应用中至关重要,软件开发需考虑高精度时间同步、数据处理、硬件接口和性能监控。
1379 60
|
11月前
|
JavaScript
时尚简洁的js轮播图特效插件
这是一款时尚简洁的js轮播图特效插件。该轮播图采用es6语法制作,底部带缩略图和描述信息。图片和描述信息在切换时同步滑动。
|
11月前
|
存储 安全 数据安全/隐私保护
深入解析iOS 14隐私保护功能:用户数据安全的新里程碑
随着数字时代的到来,个人隐私保护成为全球关注的焦点。苹果公司在最新的iOS 14系统中引入了一系列创新的隐私保护功能,旨在为用户提供更透明的数据使用信息和更强的控制权。本文将深入探讨iOS 14中的几项关键隐私功能,包括App跟踪透明性、简化的隐私设置以及增强的系统安全性,分析它们如何共同作用以提升用户的隐私保护水平。
649 3
|
Linux Go
[golang]使用gocron编写定时任务
[golang]使用gocron编写定时任务
494 0
|
算法 关系型数据库 Java
数据库原理第四章课后题答案(第四版)
数据库原理第四章课后题答案(第四版)
569 0
|
算法 数据挖掘
点球成金:数据分析对抗传统经验的超级案例 | 彭文华
点球成金:数据分析对抗传统经验的超级案例 | 彭文华