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};
    }
}

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

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

相关推荐
在未来等你11 分钟前
Kafka面试精讲 Day 16:生产者性能优化策略
大数据·分布式·面试·kafka·消息队列
·云扬·1 小时前
【Leetcode hot 100】101.对称二叉树
算法·leetcode·职场和发展
卓码软件测评2 小时前
第三方软件测试机构【性能测试工具用LoadRunner还是JMeter?】
java·功能测试·测试工具·jmeter·性能优化
Lionel_SSL6 小时前
《深入理解Java虚拟机》第三章读书笔记:垃圾回收机制与内存管理
java·开发语言·jvm
记得开心一点嘛6 小时前
手搓Springboot
java·spring boot·spring
Greedy Alg6 小时前
LeetCode 142. 环形链表 II
算法
睡不醒的kun6 小时前
leetcode算法刷题的第三十二天
数据结构·c++·算法·leetcode·职场和发展·贪心算法·动态规划
老华带你飞6 小时前
租房平台|租房管理平台小程序系统|基于java的租房系统 设计与实现(源码+数据库+文档)
java·数据库·小程序·vue·论文·毕设·租房系统管理平台
独行soc6 小时前
2025年渗透测试面试题总结-66(题目+回答)
java·网络·python·安全·web安全·adb·渗透测试
脑子慢且灵7 小时前
[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)
java·后端·servlet·tomcat·intellij-idea·web