Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
There is an undirected tree with n nodes labeled from 0 to n - 1, rooted at node 0. You are given a 2D integer array edges of length n - 1 where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree.
At every node i, there is a gate. You are also given an array of even integers amount, where amount[i] represents:
i, if amount[i] is negative, or,i, otherwise.The game goes on as follows:
0 and Bob is at node bob.0.c, then both Alice and Bob pay c / 2 each. Similarly, if the reward at the gate is c, both of them receive c / 2 each.0, he stops moving. Note that these events are independent of each other.Return the maximum net income Alice can have if she travels towards the optimal leaf node.
Example 1:
Input: edges = [[0,1],[1,2],[1,3],[3,4]], bob = 3, amount = [-2,4,2,-4,6] Output: 6 Explanation: The above diagram represents the given tree. The game goes as follows: - Alice is initially on node 0, Bob on node 3. They open the gates of their respective nodes. Alice's net income is now -2. - Both Alice and Bob move to node 1. Since they reach here simultaneously, they open the gate together and share the reward. Alice's net income becomes -2 + (4 / 2) = 0. - Alice moves on to node 3. Since Bob already opened its gate, Alice's income remains unchanged. Bob moves on to node 0, and stops moving. - Alice moves on to node 4 and opens the gate there. Her net income becomes 0 + 6 = 6. Now, neither Alice nor Bob can make any further moves, and the game ends. It is not possible for Alice to get a higher net income.
Example 2:
Input: edges = [[0,1]], bob = 1, amount = [-7280,2350] Output: -7280 Explanation: Alice follows the path 0->1 whereas Bob follows the path 1->0. Thus, Alice opens the gate at node 0 only. Hence, her net income is -7280.
Constraints:
2 <= n <= 105edges.length == n - 1edges[i].length == 20 <= ai, bi < nai != biedges represents a valid tree.1 <= bob < namount.length == namount[i] is an even integer in the range [-104, 104].Problem summary: There is an undirected tree with n nodes labeled from 0 to n - 1, rooted at node 0. You are given a 2D integer array edges of length n - 1 where edges[i] = [ai, bi] indicates that there is an edge between nodes ai and bi in the tree. At every node i, there is a gate. You are also given an array of even integers amount, where amount[i] represents: the price needed to open the gate at node i, if amount[i] is negative, or, the cash reward obtained on opening the gate at node i, otherwise. The game goes on as follows: Initially, Alice is at node 0 and Bob is at node bob. At every second, Alice and Bob each move to an adjacent node. Alice moves towards some leaf node, while Bob moves towards node 0. For every node along their path, Alice and Bob either spend money to open the gate at that node, or accept the reward. Note that: If the gate is already open, no price will be required, nor will
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Tree
[[0,1],[1,2],[1,3],[3,4]] 3 [-2,4,2,-4,6]
[[0,1]] 1 [-7280,2350]
snakes-and-ladders)time-taken-to-mark-all-nodes)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
class Solution {
private List<Integer>[] g;
private int[] amount;
private int[] ts;
private int ans = Integer.MIN_VALUE;
public int mostProfitablePath(int[][] edges, int bob, int[] amount) {
int n = edges.length + 1;
g = new List[n];
ts = new int[n];
this.amount = amount;
Arrays.setAll(g, k -> new ArrayList<>());
Arrays.fill(ts, n);
for (var e : edges) {
int a = e[0], b = e[1];
g[a].add(b);
g[b].add(a);
}
dfs1(bob, -1, 0);
ts[bob] = 0;
dfs2(0, -1, 0, 0);
return ans;
}
private boolean dfs1(int i, int fa, int t) {
if (i == 0) {
ts[i] = Math.min(ts[i], t);
return true;
}
for (int j : g[i]) {
if (j != fa && dfs1(j, i, t + 1)) {
ts[j] = Math.min(ts[j], t + 1);
return true;
}
}
return false;
}
private void dfs2(int i, int fa, int t, int v) {
if (t == ts[i]) {
v += amount[i] >> 1;
} else if (t < ts[i]) {
v += amount[i];
}
if (g[i].size() == 1 && g[i].get(0) == fa) {
ans = Math.max(ans, v);
return;
}
for (int j : g[i]) {
if (j != fa) {
dfs2(j, i, t + 1, v);
}
}
}
}
// Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
func mostProfitablePath(edges [][]int, bob int, amount []int) int {
n := len(edges) + 1
g := make([][]int, n)
for _, e := range edges {
a, b := e[0], e[1]
g[a] = append(g[a], b)
g[b] = append(g[b], a)
}
ts := make([]int, n)
for i := range ts {
ts[i] = n
}
var dfs1 func(int, int, int) bool
dfs1 = func(i, fa, t int) bool {
if i == 0 {
ts[i] = min(ts[i], t)
return true
}
for _, j := range g[i] {
if j != fa && dfs1(j, i, t+1) {
ts[j] = min(ts[j], t+1)
return true
}
}
return false
}
dfs1(bob, -1, 0)
ts[bob] = 0
ans := -0x3f3f3f3f
var dfs2 func(int, int, int, int)
dfs2 = func(i, fa, t, v int) {
if t == ts[i] {
v += amount[i] >> 1
} else if t < ts[i] {
v += amount[i]
}
if len(g[i]) == 1 && g[i][0] == fa {
ans = max(ans, v)
return
}
for _, j := range g[i] {
if j != fa {
dfs2(j, i, t+1, v)
}
}
}
dfs2(0, -1, 0, 0)
return ans
}
# Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
class Solution:
def mostProfitablePath(
self, edges: List[List[int]], bob: int, amount: List[int]
) -> int:
def dfs1(i, fa, t):
if i == 0:
ts[i] = min(ts[i], t)
return True
for j in g[i]:
if j != fa and dfs1(j, i, t + 1):
ts[j] = min(ts[j], t + 1)
return True
return False
def dfs2(i, fa, t, v):
if t == ts[i]:
v += amount[i] // 2
elif t < ts[i]:
v += amount[i]
nonlocal ans
if len(g[i]) == 1 and g[i][0] == fa:
ans = max(ans, v)
return
for j in g[i]:
if j != fa:
dfs2(j, i, t + 1, v)
n = len(edges) + 1
g = defaultdict(list)
ts = [n] * n
for a, b in edges:
g[a].append(b)
g[b].append(a)
dfs1(bob, -1, 0)
ts[bob] = 0
ans = -inf
dfs2(0, -1, 0, 0)
return ans
// Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
// Rust example auto-generated from java reference.
// Replace the signature and local types with the exact LeetCode harness for this problem.
impl Solution {
pub fn rust_example() {
// Port the logic from the reference block below.
}
}
// Reference (java):
// // Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
// class Solution {
// private List<Integer>[] g;
// private int[] amount;
// private int[] ts;
// private int ans = Integer.MIN_VALUE;
//
// public int mostProfitablePath(int[][] edges, int bob, int[] amount) {
// int n = edges.length + 1;
// g = new List[n];
// ts = new int[n];
// this.amount = amount;
// Arrays.setAll(g, k -> new ArrayList<>());
// Arrays.fill(ts, n);
// for (var e : edges) {
// int a = e[0], b = e[1];
// g[a].add(b);
// g[b].add(a);
// }
// dfs1(bob, -1, 0);
// ts[bob] = 0;
// dfs2(0, -1, 0, 0);
// return ans;
// }
//
// private boolean dfs1(int i, int fa, int t) {
// if (i == 0) {
// ts[i] = Math.min(ts[i], t);
// return true;
// }
// for (int j : g[i]) {
// if (j != fa && dfs1(j, i, t + 1)) {
// ts[j] = Math.min(ts[j], t + 1);
// return true;
// }
// }
// return false;
// }
//
// private void dfs2(int i, int fa, int t, int v) {
// if (t == ts[i]) {
// v += amount[i] >> 1;
// } else if (t < ts[i]) {
// v += amount[i];
// }
// if (g[i].size() == 1 && g[i].get(0) == fa) {
// ans = Math.max(ans, v);
// return;
// }
// for (int j : g[i]) {
// if (j != fa) {
// dfs2(j, i, t + 1, v);
// }
// }
// }
// }
// Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #2467: Most Profitable Path in a Tree
// class Solution {
// private List<Integer>[] g;
// private int[] amount;
// private int[] ts;
// private int ans = Integer.MIN_VALUE;
//
// public int mostProfitablePath(int[][] edges, int bob, int[] amount) {
// int n = edges.length + 1;
// g = new List[n];
// ts = new int[n];
// this.amount = amount;
// Arrays.setAll(g, k -> new ArrayList<>());
// Arrays.fill(ts, n);
// for (var e : edges) {
// int a = e[0], b = e[1];
// g[a].add(b);
// g[b].add(a);
// }
// dfs1(bob, -1, 0);
// ts[bob] = 0;
// dfs2(0, -1, 0, 0);
// return ans;
// }
//
// private boolean dfs1(int i, int fa, int t) {
// if (i == 0) {
// ts[i] = Math.min(ts[i], t);
// return true;
// }
// for (int j : g[i]) {
// if (j != fa && dfs1(j, i, t + 1)) {
// ts[j] = Math.min(ts[j], t + 1);
// return true;
// }
// }
// return false;
// }
//
// private void dfs2(int i, int fa, int t, int v) {
// if (t == ts[i]) {
// v += amount[i] >> 1;
// } else if (t < ts[i]) {
// v += amount[i];
// }
// if (g[i].size() == 1 && g[i].get(0) == fa) {
// ans = Math.max(ans, v);
// return;
// }
// for (int j : g[i]) {
// if (j != fa) {
// dfs2(j, i, t + 1, v);
// }
// }
// }
// }
Use this to step through a reusable interview workflow for this problem.
BFS with a queue visits every node exactly once — O(n) time. The queue may hold an entire level of the tree, which for a complete binary tree is up to n/2 nodes = O(n) space. This is optimal in time but costly in space for wide trees.
Every node is visited exactly once, giving O(n) time. Space depends on tree shape: O(h) for recursive DFS (stack depth = height h), or O(w) for BFS (queue width = widest level). For balanced trees h = log n; for skewed trees h = n.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Recursive traversal assumes children always exist.
Usually fails on: Leaf nodes throw errors or create wrong depth/path values.
Fix: Handle null/base cases before recursive transitions.