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

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

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

相关推荐
2401_85743969几秒前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6662 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索4 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
小沈熬夜秃头中୧⍤⃝4 分钟前
【贪心算法】No.1---贪心算法(1)
算法·贪心算法
芒果披萨9 分钟前
Filter和Listener
java·filter
qq_49244844614 分钟前
Java实现App自动化(Appium Demo)
java
阿华的代码王国22 分钟前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
木向36 分钟前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越38 分钟前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
skaiuijing1 小时前
Sparrow系列拓展篇:对调度层进行抽象并引入IPC机制信号量
c语言·算法·操作系统·调度算法·操作系统内核