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

废话先说

今天本来是不想打周赛的,手贱不小心报名了(其实还是想去打),前两题不说了,都是很简单的题。直到遇到第三题,我停下了手,开始不断尝试各种方法,

直到比赛结束我也没有完成,看了各路大神的解法后,才知道我是有多菜鸡。

前两题:形成两个异或相等数组的三元组数目用栈操作构建数组,第四题我一般直接放弃,除非第四题不难(那是不可能的)。

本周周赛才完成两道题。成绩惨不忍睹,以后还是乖乖打周赛算了。看着大神十几分钟做完四道题,我还得努力才是。

收集树上所有苹果的最少时间(点击标题,查看题目页)

题目

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

无向树的边由 edges 给出,其中 edges[i] = [fromi, toi] ,表示有一条边连接 from 和 toi 。除此以外,还有一个布尔数组 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 <= fromi, toi <= n-1
  • fromi < toi
  • hasApple.length == n

思路

我看了题解后发现大佬们都有一下几个解题方法:

  1. 不要从0节点出发,从是苹果的节点出发
  2. 无向树一定要转换成HashMap,这样能保证效率
  3. 没走过一条边,一定要用集合去重

好了,总结完大佬们的思路,也该来说说我的观点了,其实这题一开始我确实想复杂了,题目要求的时,我们从节点0出发,去摘苹果,摘完所有苹果后,还得回到节点0,返回花费的最少时间,总而言之就是少走路。

如果一开始从0出发的话,很好,你成功被题目带偏,如果从0出发,你将有许多种选择,你还得判断选择的正确性,不错,一开始我就是这样做的,做难受的是即使是这种最直观的做法,我也没做出来。

 

好吧,既然我无法去摘苹果,不如让苹果自动来让我摘(我可真机灵)。

总结思路如下:

  • 把edges转换成HashMap,key为当前节点,val为当前节点的父节点
  • 用一个列表来保存苹果的节点
  • 遍历苹果节点,利用HashMap找出从苹果节点到根节点(0),并且每经过一条变记得加入到集合中去重

代码(Java)

class Solution {
    public int minTime(int n, int[][] edges, List<Boolean> hasApple) {
        // 存放当前节点的父节点
        Map<Integer, Integer> map = new HashMap<>();
        // 保存经过的节点
        Set<Integer> set = new HashSet<>();
        for (int[] e: edges) map.put(e[1], e[0]);
        // 存放苹果节点
        List<Integer> apple = new ArrayList<>();
        for (int i = 0; i < n; ++i)
            if (hasApple.get(i))
                apple.add(i);
        // 没有苹果
        if (apple.size() == 0) return 0;
        // ans存放的是需要经过的节点数
        int ans = 0;
        for (int i = 0; i < apple.size(); ++i) {
            int tmp = apple.get(i);
            set.add(tmp);
            ans += 1;
            while (tmp != 0) {
                tmp = map.get(tmp);
                if (!set.contains(tmp)) {
                    set.add(tmp);
                    ans += 1;
                }
            }
        }
        // 为什么减一
        // ans存放的是需要经过的节点数,ans - 1才是经过的边的数
        return (ans - 1) * 2;
    }
}

某位大佬的做法O(N)的时间复杂度也能完成。

》》》》》传送门:这位大佬《《《《《

》》http://lock2016.xyz/blog/article/10《《

》》https://noncover.github.io/2020/05/10/%E5%8A%9B%E6%89%A35406%E6%94%B6%E9%9B%86%E6%A0%91%E4%B8%8A%E6%89%80%E6%9C%89%E8%8B%B9%E6%9E%9C%E7%9A%84%E6%9C%80%E5%B0%91%E6%97%B6%E9%97%B4/《《

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值