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.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
There is an undirected connected tree with n nodes labeled from 0 to n - 1 and n - 1 edges.
You are given a 0-indexed integer array nums of length n where nums[i] represents the value of the ith node. You are also 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.
Remove two distinct edges of the tree to form three connected components. For a pair of removed edges, the following steps are defined:
[4,5,7], [1,9], and [3,3,3]. The three XOR values are 4 ^ 5 ^ 7 = 6, 1 ^ 9 = 8, and 3 ^ 3 ^ 3 = 3. The largest XOR value is 8 and the smallest XOR value is 3. The score is then 8 - 3 = 5.Return the minimum score of any possible pair of edge removals on the given tree.
Example 1:
Input: nums = [1,5,5,4,11], edges = [[0,1],[1,2],[1,3],[3,4]] Output: 9 Explanation: The diagram above shows a way to make a pair of removals. - The 1st component has nodes [1,3,4] with values [5,4,11]. Its XOR value is 5 ^ 4 ^ 11 = 10. - The 2nd component has node [0] with value [1]. Its XOR value is 1 = 1. - The 3rd component has node [2] with value [5]. Its XOR value is 5 = 5. The score is the difference between the largest and smallest XOR value which is 10 - 1 = 9. It can be shown that no other pair of removals will obtain a smaller score than 9.
Example 2:
Input: nums = [5,5,2,4,4,2], edges = [[0,1],[1,2],[5,2],[4,3],[1,3]] Output: 0 Explanation: The diagram above shows a way to make a pair of removals. - The 1st component has nodes [3,4] with values [4,4]. Its XOR value is 4 ^ 4 = 0. - The 2nd component has nodes [1,0] with values [5,5]. Its XOR value is 5 ^ 5 = 0. - The 3rd component has nodes [2,5] with values [2,2]. Its XOR value is 2 ^ 2 = 0. The score is the difference between the largest and smallest XOR value which is 0 - 0 = 0. We cannot obtain a smaller score than 0.
Constraints:
n == nums.length3 <= n <= 10001 <= nums[i] <= 108edges.length == n - 1edges[i].length == 20 <= ai, bi < nai != biedges represents a valid tree.Problem summary: There is an undirected connected tree with n nodes labeled from 0 to n - 1 and n - 1 edges. You are given a 0-indexed integer array nums of length n where nums[i] represents the value of the ith node. You are also 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. Remove two distinct edges of the tree to form three connected components. For a pair of removed edges, the following steps are defined: Get the XOR of all the values of the nodes for each of the three components respectively. The difference between the largest XOR value and the smallest XOR value is the score of the pair. For example, say the three components have the node values: [4,5,7], [1,9], and [3,3,3]. The three XOR values are 4 ^ 5 ^ 7 = 6, 1 ^ 9 = 8, and 3 ^ 3 ^ 3 = 3. The largest XOR value is 8 and the smallest XOR value is 3.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Bit Manipulation · Tree
[1,5,5,4,11] [[0,1],[1,2],[1,3],[3,4]]
[5,5,2,4,4,2] [[0,1],[1,2],[5,2],[4,3],[1,3]]
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #2322: Minimum Score After Removals on a Tree
class Solution {
private int[] nums;
private List<Integer>[] g;
private int ans = Integer.MAX_VALUE;
private int s;
private int s1;
public int minimumScore(int[] nums, int[][] edges) {
int n = nums.length;
this.nums = nums;
g = new List[n];
Arrays.setAll(g, k -> new ArrayList<>());
for (int[] e : edges) {
int a = e[0], b = e[1];
g[a].add(b);
g[b].add(a);
}
for (int x : nums) {
s ^= x;
}
for (int i = 0; i < n; ++i) {
for (int j : g[i]) {
s1 = dfs(i, j);
dfs2(i, j);
}
}
return ans;
}
private int dfs(int i, int fa) {
int res = nums[i];
for (int j : g[i]) {
if (j != fa) {
res ^= dfs(j, i);
}
}
return res;
}
private int dfs2(int i, int fa) {
int res = nums[i];
for (int j : g[i]) {
if (j != fa) {
int s2 = dfs2(j, i);
res ^= s2;
int mx = Math.max(Math.max(s ^ s1, s2), s1 ^ s2);
int mn = Math.min(Math.min(s ^ s1, s2), s1 ^ s2);
ans = Math.min(ans, mx - mn);
}
}
return res;
}
}
// Accepted solution for LeetCode #2322: Minimum Score After Removals on a Tree
func minimumScore(nums []int, edges [][]int) int {
n := len(nums)
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)
}
s, s1 := 0, 0
ans := math.MaxInt32
for _, x := range nums {
s ^= x
}
var dfs func(i, fa int) int
dfs = func(i, fa int) int {
res := nums[i]
for _, j := range g[i] {
if j != fa {
res ^= dfs(j, i)
}
}
return res
}
var dfs2 func(i, fa int) int
dfs2 = func(i, fa int) int {
res := nums[i]
for _, j := range g[i] {
if j != fa {
s2 := dfs2(j, i)
res ^= s2
mx := max(s^s1, s2, s1^s2)
mn := min(s^s1, s2, s1^s2)
ans = min(ans, mx-mn)
}
}
return res
}
for i := 0; i < n; i++ {
for _, j := range g[i] {
s1 = dfs(i, j)
dfs2(i, j)
}
}
return ans
}
# Accepted solution for LeetCode #2322: Minimum Score After Removals on a Tree
class Solution:
def minimumScore(self, nums: List[int], edges: List[List[int]]) -> int:
def dfs(i: int, fa: int) -> int:
res = nums[i]
for j in g[i]:
if j != fa:
res ^= dfs(j, i)
return res
def dfs2(i: int, fa: int) -> int:
nonlocal s, s1, ans
res = nums[i]
for j in g[i]:
if j != fa:
s2 = dfs2(j, i)
res ^= s2
mx = max(s ^ s1, s2, s1 ^ s2)
mn = min(s ^ s1, s2, s1 ^ s2)
ans = min(ans, mx - mn)
return res
g = defaultdict(list)
for a, b in edges:
g[a].append(b)
g[b].append(a)
s = reduce(lambda x, y: x ^ y, nums)
n = len(nums)
ans = inf
for i in range(n):
for j in g[i]:
s1 = dfs(i, j)
dfs2(i, j)
return ans
// Accepted solution for LeetCode #2322: Minimum Score After Removals on a Tree
impl Solution {
pub fn minimum_score(nums: Vec<i32>, edges: Vec<Vec<i32>>) -> i32 {
let n = nums.len();
let mut g = vec![vec![]; n];
for e in edges.iter() {
let a = e[0] as usize;
let b = e[1] as usize;
g[a].push(b);
g[b].push(a);
}
let mut s1 = 0;
let mut ans = i32::MAX;
let s = nums.iter().fold(0, |acc, &x| acc ^ x);
fn dfs(i: usize, fa: usize, g: &Vec<Vec<usize>>, nums: &Vec<i32>) -> i32 {
let mut res = nums[i];
for &j in &g[i] {
if j != fa {
res ^= dfs(j, i, g, nums);
}
}
res
}
fn dfs2(
i: usize,
fa: usize,
g: &Vec<Vec<usize>>,
nums: &Vec<i32>,
s: i32,
s1: i32,
ans: &mut i32,
) -> i32 {
let mut res = nums[i];
for &j in &g[i] {
if j != fa {
let s2 = dfs2(j, i, g, nums, s, s1, ans);
res ^= s2;
let mx = (s ^ s1).max(s2).max(s1 ^ s2);
let mn = (s ^ s1).min(s2).min(s1 ^ s2);
*ans = (*ans).min(mx - mn);
}
}
res
}
for i in 0..n {
for &j in &g[i] {
s1 = dfs(i, j, &g, &nums);
dfs2(i, j, &g, &nums, s, s1, &mut ans);
}
}
ans
}
}
// Accepted solution for LeetCode #2322: Minimum Score After Removals on a Tree
function minimumScore(nums: number[], edges: number[][]): number {
const n = nums.length;
const g: number[][] = Array.from({ length: n }, () => []);
for (const [a, b] of edges) {
g[a].push(b);
g[b].push(a);
}
const s = nums.reduce((a, b) => a ^ b, 0);
let s1 = 0;
let ans = Number.MAX_SAFE_INTEGER;
function dfs(i: number, fa: number): number {
let res = nums[i];
for (const j of g[i]) {
if (j !== fa) {
res ^= dfs(j, i);
}
}
return res;
}
function dfs2(i: number, fa: number): number {
let res = nums[i];
for (const j of g[i]) {
if (j !== fa) {
const s2 = dfs2(j, i);
res ^= s2;
const mx = Math.max(s ^ s1, s2, s1 ^ s2);
const mn = Math.min(s ^ s1, s2, s1 ^ s2);
ans = Math.min(ans, mx - mn);
}
}
return res;
}
for (let i = 0; i < n; ++i) {
for (const j of g[i]) {
s1 = dfs(i, j);
dfs2(i, j);
}
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Sort the array in O(n log n), then scan for the missing or unique element by comparing adjacent pairs. Sorting requires O(n) auxiliary space (or O(1) with in-place sort but O(n log n) time remains). The sort step dominates.
Bitwise operations (AND, OR, XOR, shifts) are O(1) per operation on fixed-width integers. A single pass through the input with bit operations gives O(n) time. The key insight: XOR of a number with itself is 0, which eliminates duplicates without extra space.
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.