There is a tree (i.e., a connected, undirected graph that has no cycles) consisting of n nodes numbered from 0 to n - 1 and exactly n - 1 edges. Each node has a value associated with it, and the root of the tree is node 0.
To represent this tree, you are given an integer array nums and a 2D array edges. Each nums[i] represents the ith node's value, and each edges[j] = [uj, vj] represents an edge between nodes uj and vj in the tree.
Two values x and y are coprime if gcd(x, y) == 1 where gcd(x, y) is the greatest common divisor of x and y.
An ancestor of a node i is any other node on the shortest path from node i to the root. A node is not considered an ancestor of itself.
Return an array ans of size n, where ans[i] is the closest ancestor to node i such that nums[i] and nums[ans[i]] are coprime, or -1 if there is no such ancestor.
💡 Note:Node 0 is root (no ancestors). Node 1: gcd(3,2)=1, so ancestor is 0. Node 2: gcd(3,3)=3≠1 but gcd(3,2)=1, so ancestor is 0. Node 3: gcd(2,3)=1, so ancestor is 1.
Example 2 — Single Node
$Input:nums = [5], edges = []
›Output:[-1]
💡 Note:Only one node, which is the root, so no ancestors exist.
The key insight is to use DFS traversal while maintaining an ancestor stack organized by values. During traversal, we can quickly find the closest coprime ancestor by checking GCD with each ancestor value. Best approach is DFS with ancestor stack. Time: O(n × A × log V), Space: O(n + A) where A ≤ 50.
Common Approaches
✓
Brute Force DFS with Path Reconstruction
⏱️ Time: O(n²)
Space: O(n)
Build adjacency list, then for each node perform DFS to find path to root. For each node on this path, check if its value is coprime with current node's value and return the closest one.
Optimized DFS with Ancestor Stack
⏱️ Time: O(n × A × log(max_val))
Space: O(n + A)
Perform one DFS traversal from root, maintaining a stack of ancestors organized by value. For each node, quickly find the closest coprime ancestor by checking GCD with ancestor values.
Brute Force DFS with Path Reconstruction — Algorithm Steps
Build adjacency list from edges
For each node, find path to root using DFS
Check each ancestor on path for coprimality
Return closest coprime ancestor or -1
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Build Tree
Create adjacency list from edges
2
Find Path
For each node, find complete path from root
3
Check Ancestors
Test each ancestor for coprimality
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int graph[1000][1000];
static int graphSizes[1000];
static int result[1000];
static int nums[1000];
int gcd(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
typedef struct {
int node;
int val;
} Ancestor;
void dfs(int node, int parent, Ancestor* ancestors, int ancestorCount, int n) {
// Find closest coprime ancestor
for (int i = ancestorCount - 1; i >= 0; i--) {
int ancestorNode = ancestors[i].node;
int ancestorVal = ancestors[i].val;
if (gcd(nums[node], ancestorVal) == 1) {
result[node] = ancestorNode;
break;
}
}
// Continue DFS
ancestors[ancestorCount].node = node;
ancestors[ancestorCount].val = nums[node];
for (int i = 0; i < graphSizes[node]; i++) {
int neighbor = graph[node][i];
if (neighbor != parent) {
dfs(neighbor, node, ancestors, ancestorCount + 1, n);
}
}
}
void parseArray(const char* str, int* arr, int* size) {
*size = 0;
const char* p = str;
while (*p && *p != '[') p++;
if (*p == '[') p++;
while (*p && *p != ']') {
while (*p == ' ' || *p == ',') p++;
if (*p == ']' || *p == '\0') break;
arr[(*size)++] = (int)strtol(p, (char**)&p, 10);
}
}
void parse2DArray(const char* str, int edges[][2], int* edgesSize) {
*edgesSize = 0;
const char* p = str;
while (*p && *p != '[') p++;
if (*p == '[') p++;
while (*p && *p != ']') {
while (*p == ' ' || *p == ',') p++;
if (*p == ']' || *p == '\0') break;
if (*p == '[') {
p++;
int colCount = 0;
while (*p && *p != ']') {
while (*p == ' ' || *p == ',') p++;
if (*p == ']' || *p == '\0') break;
edges[*edgesSize][colCount++] = (int)strtol(p, (char**)&p, 10);
}
(*edgesSize)++;
if (*p == ']') p++;
}
}
}
int main() {
char line1[10000], line2[10000];
fgets(line1, sizeof(line1), stdin);
fgets(line2, sizeof(line2), stdin);
line1[strcspn(line1, "\n")] = 0;
line2[strcspn(line2, "\n")] = 0;
int numsSize;
parseArray(line1, nums, &numsSize);
if (numsSize == 1) {
printf("[-1]\n");
return 0;
}
int edges[1000][2];
int edgesSize;
parse2DArray(line2, edges, &edgesSize);
// Build adjacency list
for (int i = 0; i < numsSize; i++) {
graphSizes[i] = 0;
}
for (int i = 0; i < edgesSize; i++) {
int u = edges[i][0], v = edges[i][1];
graph[u][graphSizes[u]++] = v;
graph[v][graphSizes[v]++] = u;
}
for (int i = 0; i < numsSize; i++) {
result[i] = -1;
}
Ancestor ancestors[1000];
dfs(0, -1, ancestors, 0, numsSize);
printf("[");
for (int i = 0; i < numsSize; i++) {
printf("%d", result[i]);
if (i < numsSize - 1) printf(",");
}
printf("]\n");
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(n²)
For each of n nodes, we potentially traverse up to n ancestors, and GCD calculation is O(log(min(a,b)))
n
2n
⚠ Quadratic Growth
Space Complexity
O(n)
Adjacency list and recursion stack for DFS traversal
n
2n
⚡ Linearithmic Space
23.4K Views
MediumFrequency
~25 minAvg. Time
892 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.