2024.4.24力扣每日一题——感染二叉树需要的总时间

2024.4.24

      • 题目来源
      • 我的题解
        • [方法一 转化为图+广度优先搜索](#方法一 转化为图+广度优先搜索)
        • [方法二 记录父节点+DFS](#方法二 记录父节点+DFS)
        • [方法三 一次遍历+树的直径](#方法三 一次遍历+树的直径)

题目来源

力扣每日一题;题序:2385

我的题解

方法一 转化为图+广度优先搜索

先将树转换为图,然后进行广度优先搜索进行感染模拟
时间复杂度 :O(n)
空间复杂度:O(n)

java 复制代码
class Solution {
    int size=0;
    public int amountOfTime(TreeNode root, int start) {
        // List<Integer>[] g=createGraph(root);
        Map<Integer,List<Integer>> map=createMap(root);
        // System.out.println(map);
        Set<Integer> set=new HashSet<>();
        set.add(start);
        Queue<Integer> queue=new LinkedList<>();
        queue.offer(start);
        int res=0;
        while(!queue.isEmpty()){
            int sz=queue.size();
            for(int i=0;i<sz;i++){
                List<Integer> t=map.get(queue.poll());
                if(t==null)
                    continue;
                for(Integer e:t){
                    if(set.add(e))
                        queue.offer(e);
                }
            }
            res++;
        }
        //最后一层会多计算一次
        return res-1;
    }
    public Map<Integer,List<Integer>> createMap(TreeNode root){
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        Map<Integer,List<Integer>> map=new HashMap<>();
        while(!queue.isEmpty()){
            int sz=queue.size();
            for(int i=0;i<sz;i++){
                TreeNode tree=queue.poll();
                int t=tree.val;
                if(tree.left!=null){
                    addEdge(t,tree.left.val,map);
                    queue.offer(tree.left);
                }
                if(tree.right!=null){
                    addEdge(t,tree.right.val,map);
                    queue.offer(tree.right);
                }
            }
            size+=sz;
        }
        return map;
    }
    public void addEdge(int from,int to ,Map<Integer,List<Integer>> map){
        List<Integer> l1=map.getOrDefault(from,new ArrayList<>());
        List<Integer> l2=map.getOrDefault(to,new ArrayList<>());
        l1.add(to);
        l2.add(from);
        map.put(from,l1);
        map.put(to,l2);
    }
}
方法二 记录父节点+DFS

参考灵神的代码

首先从 root出发 DFS 这棵树,找到节点值为 start 的节点 startNode。DFS 的同时,用一个哈希表(或者数组)记录每个节点的父节点。

然后从 startNode出发 DFS 这棵树,求出二叉树的最大深度,即为答案(把 startNode 的深度当作 0)。注意除了递归左右儿子以外,还需要递归父节点。为避免重复访问节点,可以添加一个递归参数 from,表示当前节点是从节点 from 过来的,不去重复访问节点 from。
时间复杂度:O(n)

空间复杂度:O(n)

java 复制代码
class Solution {
    private TreeNode startNode;
    private final Map<TreeNode, TreeNode> fa = new HashMap<>();

    public int amountOfTime(TreeNode root, int start) {
        dfs(root, null, start);
        return maxDepth(startNode, startNode);
    }

    private void dfs(TreeNode node, TreeNode from, int start) {
        if (node == null) {
            return;
        }
        fa.put(node, from); // 记录每个节点的父节点
        if (node.val == start) {
            startNode = node; // 找到 start
        }
        dfs(node.left, node, start);
        dfs(node.right, node, start);
    }

    private int maxDepth(TreeNode node, TreeNode from) {
        if (node == null) {
            return -1; // 注意这里是 -1,因为 start 的深度为 0
        }
        int res = -1;
        if (node.left != from) {
            res = Math.max(res, maxDepth(node.left, node));
        }
        if (node.right != from) {
            res = Math.max(res, maxDepth(node.right, node));
        }
        if (fa.get(node) != from) {
            res = Math.max(res, maxDepth(fa.get(node), node));
        }
        return res + 1;
    }
}
方法三 一次遍历+树的直径

参考灵神的代码

实质就是求 以start为直径端点的树的直径
时间复杂度:O(n)

空间复杂度:O(n)

java 复制代码
class Solution {
    private int ans;

    public int amountOfTime(TreeNode root, int start) {
        dfs(root, start);
        return ans;
    }

    private int[] dfs(TreeNode node, int start) {
        if (node == null) {
            return new int[]{0, 0};
        }
        int[] leftRes = dfs(node.left, start);
        int[] rightRes = dfs(node.right, start);
        int lLen = leftRes[0], lFound = leftRes[1];
        int rLen = rightRes[0], rFound = rightRes[1];
        if (node.val == start) {
            // 计算子树 start 的最大深度
            // 注意这里和方法一的区别,max 后面没有 +1,所以算出的也是最大深度
            ans = Math.max(lLen, rLen);
            return new int[]{1, 1}; // 找到了 start
        }
        if (lFound == 1 || rFound == 1) {
            // 只有在左子树或右子树包含 start 时,才能更新答案
            ans = Math.max(ans, lLen + rLen); // 两条链拼成直径
            // 保证 start 是直径端点
            return new int[]{(lFound == 1 ? lLen : rLen) + 1, 1};
        }
        return new int[]{Math.max(lLen, rLen) + 1, 0};
    }
}

灵神是真的强!!!!!!!!!!

有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~

相关推荐
木易 士心12 小时前
MPAndroidChart 用法解析和性能优化 - Kotlin & Java 双版本
android·java·kotlin
后端小张12 小时前
SpringBoot 控制台秒变炫彩特效,秀翻同事指南!
java·后端
好家伙VCC12 小时前
**标题:发散创新:探索AR开发框架的核心技术**随着增强现实(AR)技术的飞速发展,AR开发框架成为了开发者们关注的焦
java·ar
zhuzhuxia⌓‿⌓12 小时前
线性表的顺序和链式存储
数据结构·c++·算法
chools13 小时前
学习问题日记-4
java
懒人Ethan13 小时前
解决一个C# 在Framework 4.5反序列化的问题
java·前端·c#
未知陨落13 小时前
LeetCode:95.编辑距离
算法·leetcode
2351613 小时前
【MySQL】MVCC:从核心原理到幻读解决方案
java·数据库·后端·sql·mysql·缓存
杨小码不BUG13 小时前
小鱼的数字游戏:C++实现与算法分析(洛谷P1427)
c++·算法·数组·信奥赛·csp-j/s
扶苏-su13 小时前
Java---注解
java·注解