The "Count Pairs Of Nodes" problem asks you to count the number of unique pairs of nodes in an undirected graph that satisfy a particular condition. Given:
n
representing the number of nodes, labeled from 1
to n
.[u, v]
indicating an undirected connection between nodes u
and v
.queries
, where for each queries[i]
you must count the number of pairs (a, b)
such that a < b
and the total number of edges incident to either a
or b
(counting shared edges only once) is strictly greater than queries[i]
.Key constraints:
(a, b)
is counted only once (order doesn't matter, and a < b
).To solve this problem, we first need to understand the graph representation and how to efficiently count pairs. The brute-force approach would be to check every possible pair of nodes and count their combined degree (number of edges attached to either node), then see if it exceeds the query value. However, this would be too slow for large graphs.
The challenge is that some edges may connect the same pair of nodes multiple times (multi-edges), and we should only count each edge once per pair. We also need to efficiently process multiple queries.
The optimization comes from realizing that:
deg[a] + deg[b] - shared[a][b]
, where shared[a][b]
is the number of edges directly between a
and b
.Let's break down the steps to solve the problem efficiently:
deg
.(a, b)
, count how many direct edges exist between them. Store this in a dictionary shared[(a,b)]
.(a, b)
such that deg[a] + deg[b] > queries[i]
.This approach leverages sorting and precomputation to avoid redundant calculations, making it efficient even for large graphs.
Suppose n = 4
, edges = [[1,2],[2,3],[1,3],[2,4]]
, and queries = [2,3]
.
This step-by-step process ensures we count only the valid pairs for each query.
Brute-force Approach:
The optimized approach is much more scalable for large graphs and multiple queries.
To solve the "Count Pairs Of Nodes" problem efficiently, we:
from collections import defaultdict
class Solution:
def countPairs(self, n, edges, queries):
deg = [0] * (n + 1)
shared = defaultdict(int)
for u, v in edges:
deg[u] += 1
deg[v] += 1
a, b = min(u, v), max(u, v)
shared[(a, b)] += 1
sorted_deg = sorted(deg[1:])
res = []
for q in queries:
ans = 0
l, r = 0, n - 1
while l < r:
if sorted_deg[l] + sorted_deg[r] > q:
ans += r - l
r -= 1
else:
l += 1
# Adjust for shared edges
for (a, b), cnt in shared.items():
if deg[a] + deg[b] > q and deg[a] + deg[b] - cnt <= q:
ans -= 1
res.append(ans)
return res
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<int> countPairs(int n, vector<vector<int>>& edges, vector<int>& queries) {
vector<int> deg(n + 1, 0);
unordered_map<long long, int> shared;
for (auto& e : edges) {
int u = e[0], v = e[1];
deg[u]++;
deg[v]++;
int a = min(u, v), b = max(u, v);
long long key = ((long long)a << 32) | b;
shared[key]++;
}
vector<int> sorted_deg(deg.begin() + 1, deg.end());
sort(sorted_deg.begin(), sorted_deg.end());
vector<int> res;
for (int q : queries) {
int ans = 0, l = 0, r = n - 1;
while (l < r) {
if (sorted_deg[l] + sorted_deg[r] > q) {
ans += r - l;
r--;
} else {
l++;
}
}
for (auto& it : shared) {
int a = (int)(it.first >> 32), b = (int)(it.first & 0xFFFFFFFF);
int cnt = it.second;
if (deg[a] + deg[b] > q && deg[a] + deg[b] - cnt <= q)
ans--;
}
res.push_back(ans);
}
return res;
}
};
import java.util.*;
class Solution {
public int[] countPairs(int n, int[][] edges, int[] queries) {
int[] deg = new int[n + 1];
Map<Long, Integer> shared = new HashMap<>();
for (int[] e : edges) {
int u = e[0], v = e[1];
deg[u]++;
deg[v]++;
int a = Math.min(u, v), b = Math.max(u, v);
long key = ((long)a << 32) | b;
shared.put(key, shared.getOrDefault(key, 0) + 1);
}
int[] sorted_deg = Arrays.copyOfRange(deg, 1, n + 1);
Arrays.sort(sorted_deg);
int[] res = new int[queries.length];
for (int i = 0; i < queries.length; i++) {
int q = queries[i], ans = 0, l = 0, r = n - 1;
while (l < r) {
if (sorted_deg[l] + sorted_deg[r] > q) {
ans += r - l;
r--;
} else {
l++;
}
}
for (Map.Entry<Long, Integer> entry : shared.entrySet()) {
int a = (int)(entry.getKey() >> 32), b = (int)(entry.getKey() & 0xFFFFFFFFL);
int cnt = entry.getValue();
if (deg[a] + deg[b] > q && deg[a] + deg[b] - cnt <= q)
ans--;
}
res[i] = ans;
}
return res;
}
}
var countPairs = function(n, edges, queries) {
const deg = Array(n + 1).fill(0);
const shared = new Map();
for (const [u, v] of edges) {
deg[u]++;
deg[v]++;
const a = Math.min(u, v), b = Math.max(u, v);
const key = a + ',' + b;
shared.set(key, (shared.get(key) || 0) + 1);
}
const sorted_deg = deg.slice(1).sort((a, b) => a - b);
const res = [];
for (const q of queries) {
let ans = 0, l = 0, r = n - 1;
while (l < r) {
if (sorted_deg[l] + sorted_deg[r] > q) {
ans += r - l;
r--;
} else {
l++;
}
}
for (const [key, cnt] of shared.entries()) {
const [a, b] = key.split(',').map(Number);
if (deg[a] + deg[b] > q && deg[a] + deg[b] - cnt <= q)
ans--;
}
res.push(ans);
}
return res;
};