You are given an undirected tree rooted at node 0 with n nodes numbered from 0 to n - 1, represented by a 2D array edges of length n - 1, where edges[i] = [u_i, v_i, length_i] indicates an edge between nodes u_i and v_i with length length_i.
You are also given an integer array nums, where nums[i] represents the value at node i.
A special path is defined as a downward path from an ancestor node to a descendant node such that all the values of the nodes in that path are unique.
Note that a path may start and end at the same node.
Return an array result of size 2, where result[0] is the length of the longest special path, and result[1] is the minimum number of nodes in all possible longest special paths.
The key insight is to use DFS with backtracking to explore all downward paths while maintaining a set of visited values to ensure uniqueness. Best approach uses DFS with visited set tracking for efficient path exploration. Time: O(n²), Space: O(n)
Common Approaches
✓
Sort First
⏱️ Time: N/A
Space: N/A
Frequency Count
⏱️ Time: N/A
Space: N/A
Brute Force DFS
⏱️ Time: O(n²)
Space: O(n)
For each node, explore all possible downward paths and check if values are unique. Track the maximum path length and count paths with that length.
Optimized DFS with Backtracking
⏱️ Time: O(n²)
Space: O(n)
Build the tree structure and perform DFS from root, using backtracking to efficiently explore all unique paths without redundant work.
Algorithm Steps — Algorithm Steps
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct {
int to;
int length;
} Edge;
// Use dynamic allocation instead of massive static arrays
Edge** adj;
int* adjSize;
int* nums;
bool* visited;
int maxLength = 0;
int minNodes = 0;
int n;
void dfs(int node, int currentLength, int nodeCount, bool* usedValues) {
if (currentLength > maxLength || (currentLength == maxLength && nodeCount < minNodes)) {
maxLength = currentLength;
minNodes = nodeCount;
}
for (int i = 0; i < adjSize[node]; i++) {
int child = adj[node][i].to;
int edgeLength = adj[node][i].length;
if (!visited[child] && !usedValues[nums[child]]) {
visited[child] = true;
usedValues[nums[child]] = true;
dfs(child, currentLength + edgeLength, nodeCount + 1, usedValues);
usedValues[nums[child]] = false;
visited[child] = false;
}
}
}
int* longestSpecialPath(int** edges, int edgesSize, int* nums_arr, int numsSize, int* returnSize) {
*returnSize = 2;
int* result = (int*)malloc(2 * sizeof(int));
n = numsSize;
// Dynamic allocation
adj = (Edge**)malloc(n * sizeof(Edge*));
adjSize = (int*)calloc(n, sizeof(int));
nums = (int*)malloc(n * sizeof(int));
visited = (bool*)calloc(n, sizeof(bool));
// Allocate space for adjacency lists
for (int i = 0; i < n; i++) {
adj[i] = (Edge*)malloc(n * sizeof(Edge)); // At most n-1 edges per node
}
maxLength = 0;
minNodes = 1;
for (int i = 0; i < numsSize; i++) {
nums[i] = nums_arr[i];
}
// Build adjacency list
for (int i = 0; i < edgesSize; i++) {
int u = edges[i][0];
int v = edges[i][1];
int len = edges[i][2];
adj[u][adjSize[u]].to = v;
adj[u][adjSize[u]].length = len;
adjSize[u]++;
adj[v][adjSize[v]].to = u;
adj[v][adjSize[v]].length = len;
adjSize[v]++;
}
bool* usedValues = (bool*)calloc(100005, sizeof(bool));
// Try starting from each node
for (int start = 0; start < numsSize; start++) {
memset(visited, false, n * sizeof(bool));
memset(usedValues, false, 100005 * sizeof(bool));
visited[start] = true;
usedValues[nums[start]] = true;
dfs(start, 0, 1, usedValues);
visited[start] = false;
usedValues[nums[start]] = false;
}
result[0] = maxLength;
result[1] = minNodes;
// Cleanup
for (int i = 0; i < n; i++) {
free(adj[i]);
}
free(adj);
free(adjSize);
free(nums);
free(visited);
free(usedValues);
return result;
}
void parseEdges(const char* str, int edges[][3], int* edgesSize) {
*edgesSize = 0;
const char* p = str;
// Skip to first '['
while (*p && *p != '[') p++;
if (*p == '[') p++;
while (*p && *p != ']') {
// Skip whitespace and commas
while (*p == ' ' || *p == ',' || *p == '\n' || *p == '\t') p++;
if (*p == ']') break;
if (*p == '[') {
p++; // Skip '['
// Parse three integers
edges[*edgesSize][0] = (int)strtol(p, (char**)&p, 10);
while (*p == ' ' || *p == ',') p++;
edges[*edgesSize][1] = (int)strtol(p, (char**)&p, 10);
while (*p == ' ' || *p == ',') p++;
edges[*edgesSize][2] = (int)strtol(p, (char**)&p, 10);
(*edgesSize)++;
// Skip to ']'
while (*p && *p != ']') p++;
if (*p == ']') p++;
} else {
p++;
}
}
}
void parseNums(const char* str, int* nums, int* numsSize) {
*numsSize = 0;
const char* p = str;
// Skip to first '['
while (*p && *p != '[') p++;
if (*p == '[') p++;
while (*p && *p != ']') {
while (*p == ' ' || *p == ',' || *p == '\n' || *p == '\t') p++;
if (*p == ']' || *p == '\0') break;
nums[(*numsSize)++] = (int)strtol(p, (char**)&p, 10);
}
}
int main() {
char line1[100000];
char line2[100000];
// Read edges
fgets(line1, sizeof(line1), stdin);
int edges[100000][3];
int edgesSize;
parseEdges(line1, edges, &edgesSize);
// Read nums
fgets(line2, sizeof(line2), stdin);
int nums_input[100000];
int numsSize;
parseNums(line2, nums_input, &numsSize);
// Convert edges to int**
int** edgesPtrs = (int**)malloc(edgesSize * sizeof(int*));
for (int i = 0; i < edgesSize; i++) {
edgesPtrs[i] = edges[i];
}
int returnSize;
int* result = longestSpecialPath(edgesPtrs, edgesSize, nums_input, numsSize, &returnSize);
printf("[%d,%d]\n", result[0], result[1]);
free(edgesPtrs);
free(result);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
n
2n
⚠ Quadratic Growth
Space Complexity
n
2n
⚡ Linearithmic Space
2.2K Views
MediumFrequency
~35 minAvg. Time
89 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.