二叉树_题目24:1443. 收集树上所有苹果的最少时间

22 阅读3分钟

题目24:1443. 收集树上所有苹果的最少时间

1443. 收集树上所有苹果的最少时间

同类题目

前置知识

题目描述

  • 给你一棵有 n 个节点的无向树,节点编号为 0n-1 ,它们中有一些节点有苹果。通过树上的一条边,需要花费 1 秒钟。你从 节点 0 出发,请你返回最少需要多少秒,可以收集到所有苹果,并回到节点 0 。

    无向树的边由 edges 给出,其中 edges[i] = [fromi, toi] ,表示有一条边连接 fromtoi 。除此以外,还有一个布尔数组 hasApple ,其中 hasApple[i] = true 代表节点 i 有一个苹果,否则,节点 i 没有苹果。

    示例 1:

     输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,true,true,false]
     输出:8 
     解释:上图展示了给定的树,其中红色节点表示有苹果。一个能收集到所有苹果的最优方案由绿色箭头表示。
    

    示例 2:

     输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,true,false,false,true,false]
     输出:6
     解释:上图展示了给定的树,其中红色节点表示有苹果。一个能收集到所有苹果的最优方案由绿色箭头表示。
    

    示例 3:

     输入:n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], hasApple = [false,false,false,false,false,false,false]
     输出:0
    

    提示:

    • 1 <= n <= 10^5
    • edges.length == n - 1
    • edges[i].length == 2
    • 0 <= ai < bi <= n - 1
    • hasApple.length == n

思路分析

子问题+从低往上

对于树中的每一个节点,计算收集所有该节点的所有子节点的苹果耗时

  • 图的存储使用邻接表
  • 对于树中每个节点,返回收集该节点子树中所有苹果需要的时间
  • 返回收集完当前子树的所有的苹果的总的时间

自底向上计算耗时,由于每一条边必定要走两遍,因此如果子树有苹果,那么为了返回到当前节点,这条边必走两遍,耗时为2。

每一棵树总耗时 = 所有子树耗时 + 当前节点耗时

程序代码

方法一

 //https://leetcode.cn/problems/minimum-time-to-collect-all-apples-in-a-tree/description/
 // 1443. 收集树上所有苹果的最少时间
 ​
 #include<iostream>
 #include<vector>
 using namespace std;
 class Solution {
 public:
     int dfs(vector<vector<int>>& graph, vector<bool>& visited, vector<bool>& hasApple, int node, int mycost) {
         if  ( visited[node] ) {
             return 0;
         }
         visited[node] = true;
         // 计算子树的耗时
         int child_cost = 0;
         for ( int child : graph[node] ) {
             // 计算子树的耗时
             child_cost += dfs(graph, visited, hasApple, child, 2);
         }
         // 如果当前节点的子树没有苹果并且当前节点也没有苹果,那么当前节点的子树无需遍历,耗时为0        
         if ( child_cost == 0 && !hasApple[node] ) {
             return 0;
         }
         // 当前节点子树的总耗时 = 子树耗时 + 当前节点的耗时
         return child_cost + mycost;
     }
 ​
     int minTime(int n, vector<vector<int>>& edges, vector<bool>& hasApple) {
         // 建图
         vector<vector<int>> graph(n, vector<int>());
         for ( const auto& edge : edges ) {
             graph[edge[0]].push_back(edge[1]);
             graph[edge[1]].push_back(edge[0]);
         }
         // 记录该节点是否已经访问
         vector<bool> visited(n, false);
         return dfs(graph, visited, hasApple, 0, 0);
     }
 };
 ​
 ​

复杂度分析

时间复杂度O(N),一共有 N个节点,每个节点都需要遍历一次。

空间复杂度O(N) ,主要是数组的开销。

题目感悟

更多相关知识:github.com/pingguo1987…