Skip to content

Commit 58a4611

Browse files
committed
feat: add solution 1766. Tree of Coprimes
1 parent d288dd8 commit 58a4611

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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.,&nbsp;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>&nbsp;</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>&nbsp;</p>
40+
<p><strong>Constraints:</strong></p>
41+
42+
<ul>
43+
<li><code>nums.length == n</code></li>
44+
<li><code>1 &lt;= nums[i] &lt;= 50</code></li>
45+
<li><code>1 &lt;= n &lt;= 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 &lt;= u<sub>j</sub>, v<sub>j</sub> &lt; n</code></li>
49+
<li><code>u<sub>j</sub> != v<sub>j</sub></code></li>
50+
</ul>
51+
</div>
52+
53+
<p>&nbsp;</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>&nbsp;</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+
```
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @param {number[]} nums
3+
* @param {number[][]} edges
4+
* @return {number[]}
5+
*/
6+
const getCoprimes = function (nums, edges) {
7+
const n = nums.length;
8+
const tree = Array.from({ length: n }, () => []);
9+
const maxNum = Math.max(...nums);
10+
const stack = Array.from({ length: maxNum + 1 }, () => []);
11+
const result = Array.from({ length: n }, () => -1);
12+
13+
for (const [u, v] of edges) {
14+
tree[u].push(v);
15+
tree[v].push(u);
16+
}
17+
18+
const gcd = (a, b) => (b ? gcd(b, a % b) : a);
19+
20+
const getAncestor = node => {
21+
let maxDepth = -1;
22+
let result = -1;
23+
24+
for (let num = 1; num <= maxNum; num++) {
25+
if (!stack[num].length) continue;
26+
const ancestor = stack[num].at(-1);
27+
28+
if (ancestor.depth > maxDepth && gcd(nums[node], num) === 1) {
29+
maxDepth = ancestor.depth;
30+
result = ancestor.node;
31+
}
32+
}
33+
34+
return result;
35+
};
36+
37+
const dfsTree = (node, prev, depth) => {
38+
const num = nums[node];
39+
40+
result[node] = getAncestor(node);
41+
stack[num].push({ node, depth });
42+
43+
for (const neighbor of tree[node]) {
44+
if (neighbor === prev) continue;
45+
46+
dfsTree(neighbor, node, depth + 1);
47+
}
48+
49+
stack[num].pop();
50+
};
51+
52+
dfsTree(0, -1, 0);
53+
54+
return result;
55+
};

0 commit comments

Comments
 (0)