|
| 1 | +# [1766. Tree of Coprimes](https://leetcode.com/problems/tree-of-coprimes) |
| 2 | + |
| 3 | +## Description |
| 4 | + |
| 5 | +<div class="elfjS" data-track-load="description_content"><p>There is a tree (i.e., a connected, undirected graph that has no cycles) consisting of <code>n</code> nodes numbered from <code>0</code> to <code>n - 1</code> and exactly <code>n - 1</code> edges. Each node has a value associated with it, and the <strong>root</strong> of the tree is node <code>0</code>.</p> |
| 6 | + |
| 7 | +<p>To represent this tree, you are given an integer array <code>nums</code> and a 2D array <code>edges</code>. Each <code>nums[i]</code> represents the <code>i<sup>th</sup></code> node's value, and each <code>edges[j] = [u<sub>j</sub>, v<sub>j</sub>]</code> represents an edge between nodes <code>u<sub>j</sub></code> and <code>v<sub>j</sub></code> in the tree.</p> |
| 8 | + |
| 9 | +<p>Two values <code>x</code> and <code>y</code> are <strong>coprime</strong> if <code>gcd(x, y) == 1</code> where <code>gcd(x, y)</code> is the <strong>greatest common divisor</strong> of <code>x</code> and <code>y</code>.</p> |
| 10 | + |
| 11 | +<p>An ancestor of a node <code>i</code> is any other node on the shortest path from node <code>i</code> to the <strong>root</strong>. A node is <strong>not </strong>considered an ancestor of itself.</p> |
| 12 | + |
| 13 | +<p>Return <em>an array </em><code>ans</code><em> of size </em><code>n</code>, <em>where </em><code>ans[i]</code><em> is the closest ancestor to node </em><code>i</code><em> such that </em><code>nums[i]</code> <em>and </em><code>nums[ans[i]]</code> are <strong>coprime</strong>, or <code>-1</code><em> if there is no such ancestor</em>.</p> |
| 14 | + |
| 15 | +<p> </p> |
| 16 | +<p><strong class="example">Example 1:</strong></p> |
| 17 | + |
| 18 | +<p><strong><img alt="" src="https://assets.leetcode.com/uploads/2021/01/06/untitled-diagram.png" style="width: 191px; height: 281px;"></strong></p> |
| 19 | + |
| 20 | +<pre><strong>Input:</strong> nums = [2,3,3,2], edges = [[0,1],[1,2],[1,3]] |
| 21 | +<strong>Output:</strong> [-1,0,0,1] |
| 22 | +<strong>Explanation:</strong> In the above figure, each node's value is in parentheses. |
| 23 | +- Node 0 has no coprime ancestors. |
| 24 | +- Node 1 has only one ancestor, node 0. Their values are coprime (gcd(2,3) == 1). |
| 25 | +- Node 2 has two ancestors, nodes 1 and 0. Node 1's value is not coprime (gcd(3,3) == 3), but node 0's |
| 26 | + value is (gcd(2,3) == 1), so node 0 is the closest valid ancestor. |
| 27 | +- Node 3 has two ancestors, nodes 1 and 0. It is coprime with node 1 (gcd(3,2) == 1), so node 1 is its |
| 28 | + closest valid ancestor. |
| 29 | +</pre> |
| 30 | + |
| 31 | +<p><strong class="example">Example 2:</strong></p> |
| 32 | + |
| 33 | +<p><img alt="" src="https://assets.leetcode.com/uploads/2021/01/06/untitled-diagram1.png" style="width: 441px; height: 291px;"></p> |
| 34 | + |
| 35 | +<pre><strong>Input:</strong> nums = [5,6,10,2,3,6,15], edges = [[0,1],[0,2],[1,3],[1,4],[2,5],[2,6]] |
| 36 | +<strong>Output:</strong> [-1,0,-1,0,0,0,-1] |
| 37 | +</pre> |
| 38 | + |
| 39 | +<p> </p> |
| 40 | +<p><strong>Constraints:</strong></p> |
| 41 | + |
| 42 | +<ul> |
| 43 | + <li><code>nums.length == n</code></li> |
| 44 | + <li><code>1 <= nums[i] <= 50</code></li> |
| 45 | + <li><code>1 <= n <= 10<sup>5</sup></code></li> |
| 46 | + <li><code>edges.length == n - 1</code></li> |
| 47 | + <li><code>edges[j].length == 2</code></li> |
| 48 | + <li><code>0 <= u<sub>j</sub>, v<sub>j</sub> < n</code></li> |
| 49 | + <li><code>u<sub>j</sub> != v<sub>j</sub></code></li> |
| 50 | +</ul> |
| 51 | +</div> |
| 52 | + |
| 53 | +<p> </p> |
| 54 | + |
| 55 | +## Solutions |
| 56 | + |
| 57 | +**Solution: `Depth-First Search`** |
| 58 | + |
| 59 | +- Time complexity: <em>O(n\*Max(nums))</em> |
| 60 | +- Space complexity: <em>O(n+Max(nums))</em> |
| 61 | + |
| 62 | +<p> </p> |
| 63 | + |
| 64 | +### **JavaScript** |
| 65 | + |
| 66 | +```js |
| 67 | +/** |
| 68 | + * @param {number[]} nums |
| 69 | + * @param {number[][]} edges |
| 70 | + * @return {number[]} |
| 71 | + */ |
| 72 | +const getCoprimes = function (nums, edges) { |
| 73 | + const n = nums.length; |
| 74 | + const tree = Array.from({ length: n }, () => []); |
| 75 | + const maxNum = Math.max(...nums); |
| 76 | + const stack = Array.from({ length: maxNum + 1 }, () => []); |
| 77 | + const result = Array.from({ length: n }, () => -1); |
| 78 | + |
| 79 | + for (const [u, v] of edges) { |
| 80 | + tree[u].push(v); |
| 81 | + tree[v].push(u); |
| 82 | + } |
| 83 | + |
| 84 | + const gcd = (a, b) => (b ? gcd(b, a % b) : a); |
| 85 | + |
| 86 | + const getAncestor = node => { |
| 87 | + let maxDepth = -1; |
| 88 | + let result = -1; |
| 89 | + |
| 90 | + for (let num = 1; num <= maxNum; num++) { |
| 91 | + if (!stack[num].length) continue; |
| 92 | + const ancestor = stack[num].at(-1); |
| 93 | + |
| 94 | + if (ancestor.depth > maxDepth && gcd(nums[node], num) === 1) { |
| 95 | + maxDepth = ancestor.depth; |
| 96 | + result = ancestor.node; |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + return result; |
| 101 | + }; |
| 102 | + |
| 103 | + const dfsTree = (node, prev, depth) => { |
| 104 | + const num = nums[node]; |
| 105 | + |
| 106 | + result[node] = getAncestor(node); |
| 107 | + stack[num].push({ node, depth }); |
| 108 | + |
| 109 | + for (const neighbor of tree[node]) { |
| 110 | + if (neighbor === prev) continue; |
| 111 | + |
| 112 | + dfsTree(neighbor, node, depth + 1); |
| 113 | + } |
| 114 | + |
| 115 | + stack[num].pop(); |
| 116 | + }; |
| 117 | + |
| 118 | + dfsTree(0, -1, 0); |
| 119 | + |
| 120 | + return result; |
| 121 | +}; |
| 122 | +``` |
0 commit comments