废话先说
今天本来是不想打周赛的,手贱不小心报名了(其实还是想去打),前两题不说了,都是很简单的题。直到遇到第三题,我停下了手,开始不断尝试各种方法,
直到比赛结束我也没有完成,看了各路大神的解法后,才知道我是有多菜鸡。
前两题:形成两个异或相等数组的三元组数目和用栈操作构建数组,第四题我一般直接放弃,除非第四题不难(那是不可能的)。
本周周赛才完成两道题。成绩惨不忍睹,以后还是乖乖打周赛算了。看着大神十几分钟做完四道题,我还得努力才是。
收集树上所有苹果的最少时间(点击标题,查看题目页)
题目
给你一棵有 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
思路
我看了题解后发现大佬们都有一下几个解题方法:
- 不要从0节点出发,从是苹果的节点出发
- 无向树一定要转换成HashMap,这样能保证效率
- 没走过一条边,一定要用集合去重
好了,总结完大佬们的思路,也该来说说我的观点了,其实这题一开始我确实想复杂了,题目要求的时,我们从节点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《《