Skip to content

Commit a80c741

Browse files
committed
Improved 3486
1 parent 240c8da commit a80c741

File tree

2 files changed

+59
-127
lines changed

2 files changed

+59
-127
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,67 @@
11
package g3401_3500.s3486_longest_special_path_ii;
22

3-
// #Hard #2025_03_16_Time_1831_ms_(_%)_Space_87.71_MB_(_%)
3+
// #Hard #2025_03_16_Time_178_ms_(_%)_Space_102.66_MB_(_%)
44

55
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
import java.util.Comparator;
8+
import java.util.HashMap;
69
import java.util.List;
10+
import java.util.Map;
711

812
public class Solution {
9-
private static final int MAX_VAL = 50000;
10-
private int dupCount;
11-
private int overCount;
12-
private long ansLength;
13-
private int ansNodes;
14-
private int[] nums;
15-
private List<List<int[]>> adj;
16-
private int[] path;
17-
private long[] dist;
18-
private int[] freq;
19-
2013
public int[] longestSpecialPath(int[][] edges, int[] nums) {
21-
int n = nums.length;
22-
this.nums = nums;
23-
adj = new ArrayList<>();
24-
for (int i = 0; i < n; i++) {
25-
adj.add(new ArrayList<>());
26-
}
27-
// Build the undirected tree (rooted at 0)
28-
for (int[] e : edges) {
29-
int u = e[0];
30-
int v = e[1];
31-
int w = e[2];
32-
adj.get(u).add(new int[] {v, w});
33-
adj.get(v).add(new int[] {u, w});
14+
int[] ans = {0, 1};
15+
Map<Integer, List<int[]>> graph = new HashMap<>();
16+
for (int[] edge : edges) {
17+
int a = edge[0];
18+
int b = edge[1];
19+
int c = edge[2];
20+
graph.computeIfAbsent(a, k -> new ArrayList<>()).add(new int[] {b, c});
21+
graph.computeIfAbsent(b, k -> new ArrayList<>()).add(new int[] {a, c});
3422
}
35-
// Preallocate DFS chain arrays
36-
path = new int[n];
37-
dist = new long[n];
38-
freq = new int[MAX_VAL + 1];
39-
ansLength = 0;
40-
ansNodes = Integer.MAX_VALUE;
41-
dupCount = 0;
42-
overCount = 0;
43-
// Start DFS from root, with left pointer L = 0 and current depth = 0.
44-
dfs(0, -1, 0, 0, 0);
45-
return new int[] {(int) ansLength, ansNodes};
23+
List<Integer> costs = new ArrayList<>();
24+
Map<Integer, Integer> last = new HashMap<>();
25+
dfs(0, 0, -1, new ArrayList<>(Arrays.asList(0, 0)), nums, graph, costs, last, ans);
26+
return ans;
4627
}
4728

48-
// The window [L, depth] (indices into the DFS chain) is valid if:
49-
// – overCount == 0 (no value appears 3+ times)
50-
// – dupCount <= 1 (at most one value appears exactly twice)
51-
private boolean valid() {
52-
return overCount == 0 && dupCount <= 1;
53-
}
54-
55-
// DFS parameters:
56-
// node: current node,
57-
// parent: parent in DFS tree,
58-
// curDist: cumulative distance from root to current node,
59-
// L: left pointer index of the valid window (in the DFS chain),
60-
// depth: current index in the DFS chain.
61-
private void dfs(int node, int parent, long curDist, int l, int depth) {
62-
path[depth] = node;
63-
dist[depth] = curDist;
64-
// Update frequency for current node's value.
65-
int v = nums[node];
66-
int old = freq[v];
67-
if (old == 0) {
68-
freq[v] = 1;
69-
} else if (old == 1) {
70-
freq[v] = 2;
71-
dupCount++;
72-
} else if (old == 2) {
73-
freq[v] = 3;
74-
overCount++;
75-
dupCount--;
76-
}
77-
// Save original left pointer.
78-
int origL = l;
79-
// We'll slide newL forward as needed.
80-
int newL = l;
81-
// Slide the window [newL, depth] until it is valid.
82-
while (!valid() && newL < depth) {
83-
int remNode = path[newL];
84-
int remVal = nums[remNode];
85-
if (freq[remVal] == 1) {
86-
freq[remVal] = 0;
87-
} else if (freq[remVal] == 2) {
88-
freq[remVal] = 1;
89-
dupCount--;
90-
} else if (freq[remVal] == 3) {
91-
freq[remVal] = 2;
92-
overCount--;
93-
// now this value counts as a duplicate.
94-
dupCount++;
95-
}
96-
newL++;
97-
}
98-
// Now window [newL, depth] is valid.
99-
// Compute current path length: difference of cumulative distances.
100-
long curPathLength = newL == depth ? 0L : dist[depth] - dist[newL];
101-
int nodeCount = depth - newL + 1;
102-
if (curPathLength > ansLength) {
103-
ansLength = curPathLength;
104-
ansNodes = nodeCount;
105-
} else if (curPathLength == ansLength && nodeCount < ansNodes) {
106-
ansNodes = nodeCount;
29+
private void dfs(
30+
int node,
31+
int currCost,
32+
int prev,
33+
List<Integer> left,
34+
int[] nums,
35+
Map<Integer, List<int[]>> graph,
36+
List<Integer> costs,
37+
Map<Integer, Integer> last,
38+
int[] ans) {
39+
int nodeColorIndexPrev = last.getOrDefault(nums[node], -1);
40+
last.put(nums[node], costs.size());
41+
costs.add(currCost);
42+
int diff = currCost - costs.get(left.get(0));
43+
int length = costs.size() - left.get(0);
44+
if (diff > ans[0] || (diff == ans[0] && length < ans[1])) {
45+
ans[0] = diff;
46+
ans[1] = length;
10747
}
108-
// Recurse for children using the updated left pointer newL.
109-
for (int[] p : adj.get(node)) {
110-
int child = p[0];
111-
int w = p[1];
112-
if (child == parent) {
48+
for (int[] next : graph.getOrDefault(node, new ArrayList<>())) {
49+
int nextNode = next[0];
50+
int nextCost = next[1];
51+
if (nextNode == prev) {
11352
continue;
11453
}
115-
dfs(child, node, curDist + w, newL, depth + 1);
116-
}
117-
// Backtracking: Restore frequency values for nodes removed from the window.
118-
// That is, for indices i from newL-1 downto origL, undo the removal.
119-
for (int i = newL - 1; i >= origL; i--) {
120-
int remNode = path[i];
121-
int remVal = nums[remNode];
122-
if (freq[remVal] == 0) {
123-
freq[remVal] = 1;
124-
} else if (freq[remVal] == 1) {
125-
freq[remVal] = 2;
126-
dupCount++;
127-
} else if (freq[remVal] == 2) {
128-
freq[remVal] = 3;
129-
overCount++;
130-
dupCount--;
54+
List<Integer> nextLeft = new ArrayList<>(left);
55+
if (last.containsKey(nums[nextNode])) {
56+
nextLeft.add(last.get(nums[nextNode]) + 1);
13157
}
58+
nextLeft.sort(Comparator.naturalOrder());
59+
while (nextLeft.size() > 2) {
60+
nextLeft.remove(0);
61+
}
62+
dfs(nextNode, currCost + nextCost, node, nextLeft, nums, graph, costs, last, ans);
13263
}
133-
// Finally, remove current node's contribution.
134-
if (freq[v] == 1) {
135-
freq[v] = 0;
136-
} else if (freq[v] == 2) {
137-
freq[v] = 1;
138-
dupCount--;
139-
} else if (freq[v] == 3) {
140-
freq[v] = 2;
141-
overCount--;
142-
dupCount++;
143-
}
64+
last.put(nums[node], nodeColorIndexPrev);
65+
costs.remove(costs.size() - 1);
14466
}
14567
}

src/test/java/g3401_3500/s3486_longest_special_path_ii/SolutionTest.java

+10
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,14 @@ void longestSpecialPath2() {
2828
new int[] {1, 1, 0, 2}),
2929
equalTo(new int[] {5, 2}));
3030
}
31+
32+
@Test
33+
void longestSpecialPath3() {
34+
assertThat(
35+
new Solution()
36+
.longestSpecialPath(
37+
new int[][] {{0, 2, 4}, {1, 2, 10}, {3, 1, 5}},
38+
new int[] {4, 5, 4, 5}),
39+
equalTo(new int[] {15, 3}));
40+
}
3141
}

0 commit comments

Comments
 (0)