You are given an integer n representing the number of nodes in a graph, labeled from 0 to n - 1.
You are also given an integer array nums of length n and an integer
maxDiff.
An undirected edge exists between nodes i and j if the absolute difference between nums[i] and nums[j] is at mostmaxDiff (i.e.,
|nums[i] - nums[j]| <= maxDiff).
You are also given a 2D integer array queries. For each queries[i] = [ui, vi], find the minimum distance between nodes ui and vi. If no path exists between the two nodes, return -1 for that query.
Return an array answer, where answer[i] is the result of the ith query.
Input: n =3, nums =[3,6,1], maxDiff =1, queries =[[0,0],[0,1],[1,2]]Output: [0,-1,-1]Explanation:
There are no edges between any two nodes because:* Nodes 0 and 1:`|nums[0] - nums[1]| = |3 - 6| = 3 > 1`* Nodes 0 and 2:`|nums[0] - nums[2]| = |3 - 1| = 2 > 1`* Nodes 1 and 2:`|nums[1] - nums[2]| = |6 - 1| = 5 > 1`Thus, no node can reach any other node, and the output is`[0, -1, -1]`.
The graph is defined by connecting nodes whose values differ by at most maxDiff. For each query, we need the shortest path between two nodes. Since the graph is implicit and can be very large, we avoid building the full adjacency list. Instead, we use value bucketing and BFS for each query, leveraging the fact that for each node, its neighbors are those with values in [nums[i] - maxDiff, nums[i] + maxDiff].
#include<vector>#include<queue>#include<unordered_map>#include<unordered_set>usingnamespace std;
vector<int> minimumDistance(int n, vector<int>& nums, int maxDiff, vector<vector<int>>& queries) {
unordered_map<int, vector<int>> val2idx;
for (int i =0; i < n; ++i) val2idx[nums[i]].push_back(i);
vector<int> res;
for (auto& q : queries) {
int u = q[0], v = q[1];
if (u == v) { res.push_back(0); continue; }
queue<pair<int, int>> qBFS;
unordered_set<int> visited;
qBFS.push({u, 0});
visited.insert(u);
bool found = false;
while (!qBFS.empty() &&!found) {
auto [cur, dist] = qBFS.front(); qBFS.pop();
for (int d =-maxDiff; d <= maxDiff; ++d) {
int val = nums[cur] + d;
if (val2idx.count(val)) {
for (int nei : val2idx[val]) {
if (nei == cur || visited.count(nei)) continue;
if (nei == v) { res.push_back(dist +1); found = true; break; }
visited.insert(nei);
qBFS.push({nei, dist +1});
}
}
if (found) break;
}
}
if (!found) res.push_back(-1);
}
return res;
}
import java.util.*;
classSolution {
public List<Integer>minimumDistance(int n, int[] nums, int maxDiff, int[][] queries) {
Map<Integer, List<Integer>> val2idx =new HashMap<>();
for (int i = 0; i < n; ++i) val2idx.computeIfAbsent(nums[i], k ->new ArrayList<>()).add(i);
List<Integer> res =new ArrayList<>();
for (int[] q : queries) {
int u = q[0], v = q[1];
if (u == v) { res.add(0); continue; }
Queue<int[]> qBFS =new LinkedList<>();
Set<Integer> visited =new HashSet<>();
qBFS.offer(newint[]{u, 0});
visited.add(u);
boolean found =false;
while (!qBFS.isEmpty() &&!found) {
int[] node = qBFS.poll();
int cur = node[0], dist = node[1];
for (int d =-maxDiff; d <= maxDiff; ++d) {
int val = nums[cur]+ d;
if (val2idx.containsKey(val)) {
for (int nei : val2idx.get(val)) {
if (nei == cur || visited.contains(nei)) continue;
if (nei == v) { res.add(dist + 1); found =true; break; }
visited.add(nei);
qBFS.offer(newint[]{nei, dist + 1});
}
}
if (found) break;
}
}
if (!found) res.add(-1);
}
return res;
}
}
funminimumDistance(n: Int, nums: IntArray, maxDiff: Int, queries: Array<IntArray>): List<Int> {
val val2idx = mutableMapOf<Int, MutableList<Int>>()
for (i in0 until n) val2idx.getOrPut(nums[i]) { mutableListOf() }.add(i)
val res = mutableListOf<Int>()
for (q in queries) {
val u = q[0]; val v = q[1]
if (u == v) { res.add(0); continue }
val visited = mutableSetOf<Int>()
val queue = ArrayDeque<Pair<Int, Int>>()
queue.add(u to 0)
visited.add(u)
var found = falsewhile (queue.isNotEmpty() && !found) {
val(cur, dist) = queue.removeFirst()
for (d in -maxDiff..maxDiff) {
val valN = nums[cur] + d
val2idx[valN]?.forEach { nei ->if (nei == cur || nei in visited) return@forEachif (nei == v) { res.add(dist + 1); found = true; return@forEach }
visited.add(nei)
queue.add(nei to dist + 1)
}
if (found) break }
}
if (!found) res.add(-1)
}
return res
}
from collections import defaultdict, deque
from typing import List
defminimumDistance(n: int, nums: List[int], maxDiff: int, queries: List[List[int]]) -> List[int]:
val2idx = defaultdict(list)
for i, v in enumerate(nums):
val2idx[v].append(i)
res = []
for u, v in queries:
if u == v:
res.append(0)
continue visited = set([u])
q = deque([(u, 0)])
found =Falsewhile q andnot found:
cur, dist = q.popleft()
for d in range(-maxDiff, maxDiff +1):
val = nums[cur] + d
for nei in val2idx.get(val, []):
if nei == cur or nei in visited:
continueif nei == v:
res.append(dist +1)
found =Truebreak visited.add(nei)
q.append((nei, dist +1))
if found:
breakifnot found:
res.append(-1)
return res
use std::collections::{HashMap, HashSet, VecDeque};
pubfnminimum_distance(n: i32, nums: Vec<i32>, max_diff: i32, queries: Vec<Vec<i32>>) -> Vec<i32> {
letmut val2idx: HashMap<i32, Vec<usize>>= HashMap::new();
for (i, &v) in nums.iter().enumerate() {
val2idx.entry(v).or_default().push(i);
}
letmut res = Vec::new();
for q in queries.iter() {
let (u, v) = (q[0] asusize, q[1] asusize);
if u == v { res.push(0); continue; }
letmut visited = HashSet::new();
letmut queue = VecDeque::new();
queue.push_back((u, 0));
visited.insert(u);
letmut found =false;
whilelet Some((cur, dist)) = queue.pop_front() {
for d in-max_diff..=max_diff {
let val = nums[cur] + d;
iflet Some(neis) = val2idx.get(&val) {
for&nei in neis {
if nei == cur || visited.contains(&nei) { continue; }
if nei == v { res.push(dist +1); found =true; break; }
visited.insert(nei);
queue.push_back((nei, dist +1));
}
}
if found { break; }
}
if found { break; }
}
if!found { res.push(-1); }
}
res
}
⏰ Time complexity: For each query, in the worst case, O(n * maxDiff) (but usually much less if the graph is sparse or maxDiff is small). For all queries: O(Q * n * maxDiff) in the worst case, but typically much faster in practice.
🧺 Space complexity: O(n + Q) for value mapping and visited sets.