Boundary update without `+1` / `-1`
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.
Move from brute-force thinking to an efficient approach using binary search strategy.
You are given two integers, n and threshold, as well as a directed weighted graph of n nodes numbered from 0 to n - 1. The graph is represented by a 2D integer array edges, where edges[i] = [Ai, Bi, Wi] indicates that there is an edge going from node Ai to node Bi with weight Wi.
You have to remove some edges from this graph (possibly none), so that it satisfies the following conditions:
threshold outgoing edges.Return the minimum possible value of the maximum edge weight after removing the necessary edges. If it is impossible for all conditions to be satisfied, return -1.
Example 1:
Input: n = 5, edges = [[1,0,1],[2,0,2],[3,0,1],[4,3,1],[2,1,1]], threshold = 2
Output: 1
Explanation:
Remove the edge 2 -> 0. The maximum weight among the remaining edges is 1.
Example 2:
Input: n = 5, edges = [[0,1,1],[0,2,2],[0,3,1],[0,4,1],[1,2,1],[1,4,1]], threshold = 1
Output: -1
Explanation:
It is impossible to reach node 0 from node 2.
Example 3:
Input: n = 5, edges = [[1,2,1],[1,3,3],[1,4,5],[2,3,2],[3,4,2],[4,0,1]], threshold = 1
Output: 2
Explanation:
Remove the edges 1 -> 3 and 1 -> 4. The maximum weight among the remaining edges is 2.
Example 4:
Input: n = 5, edges = [[1,2,1],[1,3,3],[1,4,5],[2,3,2],[4,0,1]], threshold = 1
Output: -1
Constraints:
2 <= n <= 1051 <= threshold <= n - 11 <= edges.length <= min(105, n * (n - 1) / 2).edges[i].length == 30 <= Ai, Bi < nAi != Bi1 <= Wi <= 106Problem summary: You are given two integers, n and threshold, as well as a directed weighted graph of n nodes numbered from 0 to n - 1. The graph is represented by a 2D integer array edges, where edges[i] = [Ai, Bi, Wi] indicates that there is an edge going from node Ai to node Bi with weight Wi. You have to remove some edges from this graph (possibly none), so that it satisfies the following conditions: Node 0 must be reachable from all other nodes. The maximum edge weight in the resulting graph is minimized. Each node has at most threshold outgoing edges. Return the minimum possible value of the maximum edge weight after removing the necessary edges. If it is impossible for all conditions to be satisfied, return -1.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Binary Search
5 [[1,0,1],[2,0,2],[3,0,1],[4,3,1],[2,1,1]] 2
5 [[0,1,1],[0,2,2],[0,3,1],[0,4,1],[1,2,1],[1,4,1]] 1
5 [[1,2,1],[1,3,3],[1,4,5],[2,3,2],[3,4,2],[4,0,1]] 1
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3419: Minimize the Maximum Edge Weight of Graph
class Solution {
public int minMaxWeight(int n, int[][] pairs, int threshold) {
final int MAX = 1_000_000;
List<Pair<Integer, Integer>>[] reversedGraph = new List[n];
for (int i = 0; i < n; i++)
reversedGraph[i] = new ArrayList<>();
for (int[] pair : pairs) {
final int u = pair[0];
final int v = pair[1];
final int w = pair[2];
reversedGraph[v].add(new Pair<>(u, w));
}
int l = 1;
int r = MAX + 1;
while (l < r) {
final int m = (l + r) / 2;
if (dfs(reversedGraph, 0, m, new boolean[n]) == n)
r = m;
else
l = m + 1;
}
return l == (MAX + 1) ? -1 : l;
}
// Returns the number of nodes reachable from u with weight <= maxWeight.
private int dfs(List<Pair<Integer, Integer>>[] reversedGraph, int u, int maxWeight,
boolean[] seen) {
int res = 1;
seen[u] = true;
for (Pair<Integer, Integer> pair : reversedGraph[u]) {
final int v = pair.getKey();
final int w = pair.getValue();
if (w > maxWeight || seen[v])
continue;
res += dfs(reversedGraph, v, maxWeight, seen);
}
return res;
}
}
// Accepted solution for LeetCode #3419: Minimize the Maximum Edge Weight of Graph
package main
import (
"container/heap"
"math"
"slices"
"sort"
)
// https://space.bilibili.com/206214
func minMaxWeight(n int, edges [][]int, _ int) int {
if len(edges) < n-1 {
return -1
}
type edge struct{ to, w int }
g := make([][]edge, n)
for _, e := range edges {
x, y, w := e[0], e[1], e[2]
g[y] = append(g[y], edge{x, w})
}
dis := make([]int, n)
for i := range dis {
dis[i] = math.MaxInt
}
dis[0] = 0
h := hp{{}}
for len(h) > 0 {
p := heap.Pop(&h).(pair)
x := p.x
d := p.dis
if d > dis[x] {
continue
}
for _, e := range g[x] {
y := e.to
newD := max(d, e.w)
if newD < dis[y] {
dis[y] = newD
heap.Push(&h, pair{newD, y})
}
}
}
ans := slices.Max(dis)
if ans == math.MaxInt {
return -1
}
return ans
}
type pair struct{ dis, x int }
type hp []pair
func (h hp) Len() int { return len(h) }
func (h hp) Less(i, j int) bool { return h[i].dis < h[j].dis }
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v any) { *h = append(*h, v.(pair)) }
func (h *hp) Pop() (v any) { a := *h; *h, v = a[:len(a)-1], a[len(a)-1]; return }
func minMaxWeight2(n int, edges [][]int, _ int) int {
if len(edges) < n-1 {
return -1
}
type edge struct{ to, w int }
g := make([][]edge, n)
maxW := 0
for _, e := range edges {
x, y, w := e[0], e[1], e[2]
g[y] = append(g[y], edge{x, w})
maxW = max(maxW, w)
}
vis := make([]int, n)
ans := 1 + sort.Search(maxW, func(upper int) bool {
upper++
left := n
var dfs func(int)
dfs = func(x int) {
vis[x] = upper
left--
for _, e := range g[x] {
if e.w <= upper && vis[e.to] != upper {
dfs(e.to)
}
}
}
dfs(0)
return left == 0
})
if ans > maxW {
ans = -1
}
return ans
}
# Accepted solution for LeetCode #3419: Minimize the Maximum Edge Weight of Graph
class Solution:
def minMaxWeight(self, n: int, edges: list[list[int]], threshold: int) -> int:
MAX = 1000000
reversedGraph = [[] for _ in range(n)]
for u, v, w in edges:
reversedGraph[v].append((u, w))
l = 1
r = MAX + 1
while l < r:
m = (l + r) // 2
if self._dfs(reversedGraph, 0, m, set()) == n:
r = m
else:
l = m + 1
return -1 if l == MAX + 1 else l
def _dfs(
self,
reversedGraph: list[list[tuple]],
u: int,
maxWeight: int,
seen: set[int]
) -> int:
"""Returns the number of nodes reachable from u with weight <= maxWeight."""
res = 1
seen.add(u)
for v, w in reversedGraph[u]:
if w > maxWeight or v in seen:
continue
res += self._dfs(reversedGraph, v, maxWeight, seen)
return res
// Accepted solution for LeetCode #3419: Minimize the Maximum Edge Weight of Graph
// 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 #3419: Minimize the Maximum Edge Weight of Graph
// class Solution {
// public int minMaxWeight(int n, int[][] pairs, int threshold) {
// final int MAX = 1_000_000;
// List<Pair<Integer, Integer>>[] reversedGraph = new List[n];
//
// for (int i = 0; i < n; i++)
// reversedGraph[i] = new ArrayList<>();
//
// for (int[] pair : pairs) {
// final int u = pair[0];
// final int v = pair[1];
// final int w = pair[2];
// reversedGraph[v].add(new Pair<>(u, w));
// }
//
// int l = 1;
// int r = MAX + 1;
//
// while (l < r) {
// final int m = (l + r) / 2;
// if (dfs(reversedGraph, 0, m, new boolean[n]) == n)
// r = m;
// else
// l = m + 1;
// }
//
// return l == (MAX + 1) ? -1 : l;
// }
//
// // Returns the number of nodes reachable from u with weight <= maxWeight.
// private int dfs(List<Pair<Integer, Integer>>[] reversedGraph, int u, int maxWeight,
// boolean[] seen) {
// int res = 1;
// seen[u] = true;
// for (Pair<Integer, Integer> pair : reversedGraph[u]) {
// final int v = pair.getKey();
// final int w = pair.getValue();
// if (w > maxWeight || seen[v])
// continue;
// res += dfs(reversedGraph, v, maxWeight, seen);
// }
// return res;
// }
// }
// Accepted solution for LeetCode #3419: Minimize the Maximum Edge Weight of Graph
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #3419: Minimize the Maximum Edge Weight of Graph
// class Solution {
// public int minMaxWeight(int n, int[][] pairs, int threshold) {
// final int MAX = 1_000_000;
// List<Pair<Integer, Integer>>[] reversedGraph = new List[n];
//
// for (int i = 0; i < n; i++)
// reversedGraph[i] = new ArrayList<>();
//
// for (int[] pair : pairs) {
// final int u = pair[0];
// final int v = pair[1];
// final int w = pair[2];
// reversedGraph[v].add(new Pair<>(u, w));
// }
//
// int l = 1;
// int r = MAX + 1;
//
// while (l < r) {
// final int m = (l + r) / 2;
// if (dfs(reversedGraph, 0, m, new boolean[n]) == n)
// r = m;
// else
// l = m + 1;
// }
//
// return l == (MAX + 1) ? -1 : l;
// }
//
// // Returns the number of nodes reachable from u with weight <= maxWeight.
// private int dfs(List<Pair<Integer, Integer>>[] reversedGraph, int u, int maxWeight,
// boolean[] seen) {
// int res = 1;
// seen[u] = true;
// for (Pair<Integer, Integer> pair : reversedGraph[u]) {
// final int v = pair.getKey();
// final int w = pair.getValue();
// if (w > maxWeight || seen[v])
// continue;
// res += dfs(reversedGraph, v, maxWeight, seen);
// }
// return res;
// }
// }
Use this to step through a reusable interview workflow for this problem.
Check every element from left to right until we find the target or exhaust the array. Each comparison is O(1), and we may visit all n elements, giving O(n). No extra space needed.
Each comparison eliminates half the remaining search space. After k comparisons, the space is n/2ᵏ. We stop when the space is 1, so k = log₂ n. No extra memory needed — just two pointers (lo, hi).
Review these before coding to avoid predictable interview regressions.
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.