• 1766. 互质树 DFS+桶


    1766. 互质

    给你一个 n 个节点的树(也就是一个无环连通无向图),节点编号从 0 到 n - 1 ,且恰好有 n - 1 条边,每个节点有一个值。树的 根节点 为 0 号点。

    给你一个整数数组 nums 和一个二维数组 edges 来表示这棵树。nums[i] 表示第 i 个点的值,edges[j] = [uj, vj] 表示节点 uj 和节点 vj 在树中有一条边。

    当 gcd(x, y) == 1 ,我们称两个数 x 和 y 是 互质的 ,其中 gcd(x, y) 是 x 和 y 的 最大公约数 。

    从节点 i 到  最短路径上的点都是节点 i 的祖先节点。一个节点 不是 它自己的祖先节点。

    请你返回一个大小为 n 的数组 ans ,其中 ans[i]是离节点 i 最近的祖先节点且满足 nums[i] 和 nums[ans[i]] 是 互质的 ,如果不存在这样的祖先节点,ans[i] 为 -1 。

    示例 1:

    输入:nums = [2,3,3,2], edges = [[0,1],[1,2],[1,3]]
    输出:[-1,0,0,1]
    解释:上图中,每个节点的值在括号中表示。
    - 节点 0 没有互质祖先。
    - 节点 1 只有一个祖先节点 0 。它们的值是互质的(gcd(2,3) == 1)。
    - 节点 2 有两个祖先节点,分别是节点 1 和节点 0 。节点 1 的值与它的值不是互质的(gcd(3,3) == 3)但节点 0 的值是互质的(gcd(2,3) == 1),所以节点 0 是最近的符合要求的祖先节点。
    - 节点 3 有两个祖先节点,分别是节点 1 和节点 0 。它与节点 1 互质(gcd(3,2) == 1),所以节点 1 是离它最近的符合要求的祖先节点。
    

    示例 2:

    输入:nums = [5,6,10,2,3,6,15], edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6]]
    输出:[-1,0,-1,0,0,0,-1]
    

    提示:

    • nums.length == n
    • 1 <= nums[i] <= 50
    • 1 <= n <= 1e5
    • edges.length == n - 1
    • edges[j].length == 2
    • 0 <= uj, vj < n
    • uj != vj

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

    做题结果

    成功, 一开始写dfs,没注意1e5的问题,超时,草率了。num值只有50,所以可以用哈希和桶处理,很有意思的题目。

    方法:DFS+桶

    1.50个数预处理是否互质,直接用 50*50 的二维数组保存

    2. 用边合成图

    3. dfs求解

    3. 特殊优化:由于只有50个值,只要最近的祖先。那么对于相同值的两个祖先只选最近的,所以后遍历的更深的同值元素可以替代之前的。用个哈希代表桶即可,每个桶装索引和深度,由于是1-50,也可以直接用数组表示

    4. 比较,桶内满足是互质的元素中,选取最深的元素,把当前的父节点填为这个元素即可

    1. class Solution {
    2. boolean [][]isPrime = new boolean[51][51];
    3. int[] ans;
    4. int[] nums;
    5. public int[] getCoprimes(int[] nums, int[][] edges) {
    6. for(int i = 1; i <= 50; i++) Arrays.fill(isPrime[i],true);
    7. for(int i = 2; i <= 50; i++){
    8. for(int j = i; j<=50; j++){
    9. int gcd = gcd(i,j);
    10. if(gcd!=1) isPrime[i][j]=isPrime[j][i] = false;
    11. }
    12. }
    13. this.nums = nums;
    14. int n = nums.length;
    15. ans = new int[n];
    16. Arrays.fill(ans,-1);
    17. Set []graph = new HashSet[n];
    18. Arrays.setAll(graph,o->new HashSet<>());
    19. for(int []edge:edges){
    20. int a = edge[0];
    21. int b = edge[1];
    22. graph[a].add(b);
    23. graph[b].add(a);
    24. }
    25. fillGCD(graph,new HashMap<>(),0,-1,1);
    26. return ans;
    27. }
    28. private void fillGCD(Set []graph, Mapint[]> parents, int index,int p,int deep){
    29. int n = parents.size();
    30. int maxDeep = -1;
    31. int id = -1;
    32. for(int key:parents.keySet()){
    33. if(isPrime[key][nums[index]]&&parents.get(key)[1]>maxDeep){
    34. int[] item = parents.get(key);
    35. maxDeep = item[1];
    36. id = item[0];
    37. }
    38. }
    39. ans[index] = id;
    40. int[] pre = parents.getOrDefault(nums[index],new int[]{-1,-1});
    41. parents.put(nums[index],new int[]{index,deep});
    42. for(int next:graph[index]){
    43. if(next==p) continue;
    44. fillGCD(graph,parents,next,index,deep+1);
    45. }
    46. parents.put(nums[index],pre);
    47. }
    48. private int gcd(int a, int b){
    49. return b==0?a:gcd(b,a%b);
    50. }
    51. }

  • 相关阅读:
    字典树——最大异或对(模板)
    谁有软件测试面试真题(完整答案)?正在找工作的可以收藏一下!
    这次把怎么做好一个PPT讲清-画图篇
    BUUCTF [MRCTF2020]Ez_bypass1
    关于安卓Handler内存泄漏及解决方案
    Kubernetes(K8s)使用 kubeadm 方式搭建多 master 高可用 K8s 集群
    设计模式:依赖倒转原则(Dependency Inversion Principle,DIP)介绍
    开源/免费敏捷管理工具大全
    滴滴一面:线程池任务,如何设置优先级?
    【Linux操作系统】——配置安装系统环境
  • 原文地址:https://blog.csdn.net/yu_duan_hun/article/details/126650973