LeetCode

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

题目

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-time-to-collect-all-apples-in-a-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

根据题目信息建立邻接表,基于后序遍历(自身节点最后处理)的信息传递。

采用DFS,对于与当前节点邻接的邻接点有以下情况

  1. 叶子点,仅有一条路径,这条路径是通往当前节点的。
  2. 非叶子点,有两条路径以上(包括两条)

对于当前节点的子路径,最少时间计算有以下情况。
子路径中直接与当前节点邻接的点记为连接点。

  1. 子路径是叶子点:
    • 如果有苹果,通过 时间+2。
  2. 子路径非叶子点:
    • 设tmp为收集子子路径们所有苹果的最少时间,时间 + temp + 2(要通过连接点)
  3. 子路径不是叶子点,且 子子路径们(当前节点的子路径的所有的子路径)都没有苹果。
    • 如果连接点有苹果,通过 时间 + 2

前方高能,灵魂画手。
叶子点、非叶子点和子路径不存在:

3中计算时间的情况:

代码


var minTime = function (n, edges, hasApple) {
  const map = {};
  edges.map((value, index) => {
    if (map[value[0]]) map[value[0]].push(value[1]);
    else map[value[0]] = [value[1]];
    if (map[value[1]]) map[value[1]].push(value[0]);
    else map[value[1]] = [value[0]];
  });
  const dfs = (rec, par, chi, b) => {
    // 处理叶子点,这里返回-2是与非叶子进行区分。
    if (rec[chi].length == 1 && rec[chi][0] == par && b[chi]) return -2;
    if (rec[chi].length == 1 && rec[chi][0] == par && !b[chi]) return 0;
    let ans = 0;
    for (let i = 0; i < rec[chi].length; ++i) {
      // 避免 图:往回走,树:往上走
      if (rec[chi][i] != par) {
        let tmp = dfs(rec, chi, rec[chi][i], b);
        // 处理三种情况,叶子点(连接点)上有苹果
        if (tmp < 0) ans += 2;
        // 子路径上有苹果,不管连接上有没有苹果都要经过连接点
        else if (tmp > 0) ans += tmp + 2;
        // 所有子路径上没有苹果(只有连接点有苹果不算),但连接点上有苹果。
        else if (b[rec[chi][i]]) ans += 2;
      }
    }
    return ans;
  };
  return dfs(map, -1, 0, hasApple);
};

说明

判断叶子点:
邻接表长度为1,且仅有的一个邻接点为上次的入口点。

rec[chi].length == 1&& rec[chi][0] == par; 

避免从子路径进入当前临界点的子路径(往回走)。

rec[chi][i] != par

参考:

这种题目很多都是基于后续遍历的信息传递
dfs返回的是此子树摘苹果需要的路径ans
如果一个点的子节点ans大于0,则说明摘时必经此子树,因此本节点ans需要+2
如果一个点的子节点ans等于0,并且此节点为false,则说明摘时不必经过此子树
如果一个点的子节点ans等于0,并且此节点为true,则说明摘时需要经过此子节点,本节点ans需要+2
综上所示可以写出下面的代码。

作者:bubbly-4
链接:https://leetcode-cn.com/problems/minimum-time-to-collect-all-apples-in-a-tree/solution/jian-jian-dan-dan-20xing-dai-ma-ji-yu-hou-xu-bian-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

原文地址:https://www.cnblogs.com/xiaoxu-xmy/p/13836046.html

原文地址:https://www.cnblogs.com/xiaoxu-xmy/p/13836046.html