Count Pairs of Points With Distance k
MedPrompt
You are given a 2D integer array coordinates and an integer k, where coordinates[i] = [xi, yi] are the coordinates of the ith point in a 2D plane.
We define the distance between two points (x1, y1) and (x2, y2) as (x1 XOR x2) + (y1 XOR y2) where XOR is the bitwise XOR operation.
Return the number of pairs (i, j) such that i < j and the distance between points i and j is equal to k.
Example 1:
Input: coordinates = [[1,2],[4,2],[1,3],[5,2]], k = 5
Output: 2
Explanation: We can choose the following pairs:
- (0,1): Because we have (1 XOR 4) + (2 XOR 2) = 5.
- (2,3): Because we have (1 XOR 5) + (3 XOR 2) = 5.Example 2:
Input: coordinates = [[1,3],[1,3],[1,3],[1,3],[1,3]], k = 0
Output: 10
Explanation: Any two chosen pairs will have a distance of 0. There are 10 ways to choose two pairs.
Constraints:
2 <= coordinates.length <= 500000 <= xi, yi <= 1060 <= k <= 100
Approaches
2 approaches with complexity analysis and trade-offs.
The brute-force approach is the most straightforward way to solve the problem. It involves iterating through every possible unique pair of points, calculating their distance as defined in the problem, and checking if this distance equals k. If it does, we increment a counter.
Algorithm
- Initialize a counter
countto 0. - Get the number of points,
n. - Use a nested loop structure. The outer loop runs from
i = 0ton-2. - The inner loop runs from
j = i + 1ton-1. This ensures each pair of points(i, j)is considered exactly once withi < j. - Inside the inner loop, retrieve the coordinates for point
i(x1,y1) and pointj(x2,y2). - Calculate the distance:
dist = (x1 XOR x2) + (y1 XOR y2). - If
distis equal tok, increment thecount. - After the loops complete, return
count.
Walkthrough
We can implement this using two nested loops. The outer loop iterates through each point from the beginning of the array, and the inner loop iterates through the subsequent points. This ensures that we consider every pair (i, j) such that i < j exactly once, avoiding duplicate pairs and self-comparisons.
For each pair of points (x1, y1) and (x2, y2), we compute the distance (x1 ^ x2) + (y1 ^ y2). If this sum equals k, we've found a valid pair and increment our total count.
class Solution { public int countPairs(int[][] coordinates, int k) { int n = coordinates.length; int count = 0; for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int x1 = coordinates[i][0]; int y1 = coordinates[i][1]; int x2 = coordinates[j][0]; int y2 = coordinates[j][1]; if ((x1 ^ x2) + (y1 ^ y2) == k) { count++; } } } return count; }}Complexity
Time
O(N^2), where N is the number of points in the `coordinates` array. The nested loops lead to a quadratic number of comparisons, making this approach too slow for the problem's constraints (N up to 50000).
Space
O(1). We only use a few variables to keep track of indices and the count, so the space used is constant and does not depend on the input size.
Trade-offs
Pros
Simple to understand and implement.
Requires minimal extra memory (constant space complexity).
Cons
Highly inefficient for large inputs due to its quadratic time complexity.
Will likely result in a 'Time Limit Exceeded' (TLE) error on competitive programming platforms for the given constraints.
A much more efficient approach uses a hash map to optimize the search for pairs. The key idea is to rephrase the condition (x1 ^ x2) + (y1 ^ y2) = k. For a given point (x1, y1), we need to find the number of other points (x2, y2) that satisfy this equation. We can iterate through all possible ways the integer k can be split into two non-negative integers, i and k-i. Then, for each split, we check if there's a point (x2, y2) such that x1 ^ x2 = i and y1 ^ y2 = k - i.
Algorithm
- Initialize a counter
count = 0and a hash mappointCountsto store the frequency of points encountered. - Iterate through each point
(x1, y1)in thecoordinatesarray. - For each point, iterate through all possible values of
ifrom0tok.- Let
x_xor_val = iandy_xor_val = k - i. - We are looking for a previously seen point
(x2, y2)wherex2 = x1 ^ x_xor_valandy2 = y1 ^ y_xor_val. - Calculate this target point
(x2, y2). - Create a unique key for the target point (e.g., by packing
x2andy2into along). - Look up this key in
pointCounts. If it exists, add its value (frequency) tocount.
- Let
- After checking all possible splits of
kfor the current point(x1, y1), add it to thepointCountsmap. Create a key for(x1, y1)and increment its frequency in the map. - Return
countafter iterating through all points.
Walkthrough
We process the points one by one. For each point p1 = (x1, y1), we query for partners that have been seen before it. This avoids double counting and satisfies the i < j condition implicitly.
The equation (x1 ^ x2) + (y1 ^ y2) = k can be broken down. Let x_diff = x1 ^ x2 and y_diff = y1 ^ y2. We need x_diff + y_diff = k. Since k is small (<= 100), we can iterate through all possible values for x_diff from 0 to k. If x_diff = i, then y_diff must be k - i.
This means for a given (x1, y1), we are looking for a point (x2, y2) where x2 = x1 ^ i and y2 = y1 ^ (k-i). We can use a hash map to store the frequencies of points we have already visited. For each point, we iterate from i = 0 to k, calculate the required (x2, y2), and check our map for its frequency, adding it to our total count. After checking, we add the current point to the map.
To use a Point object as a key in a Java HashMap, we need to pack the two integer coordinates into a single primitive type like long for efficiency. Since x and y are at most 10^6, they can each be represented by 20 bits. We can pack them into a 64-bit long by shifting one coordinate.
import java.util.HashMap;import java.util.Map; class Solution { public int countPairs(int[][] coordinates, int k) { // Map to store frequency of points. Key is a packed long, value is count. Map<Long, Integer> pointCounts = new HashMap<>(); int count = 0; for (int[] p : coordinates) { int x1 = p[0]; int y1 = p[1]; // Iterate through all possible values for the x-component of the distance. for (int i = 0; i <= k; i++) { int x_xor_val = i; int y_xor_val = k - i; // Calculate the coordinates of the target point (x2, y2). int x2 = x1 ^ x_xor_val; int y2 = y1 ^ y_xor_val; // Pack (x2, y2) into a long to use as a map key. // x, y <= 10^6, which is < 2^20. Shifting by 21 is safe. long key = ((long)x2 << 21) | y2; // Add the number of times we've seen this target point. count += pointCounts.getOrDefault(key, 0); } // Add the current point to the map for subsequent checks. long currentKey = ((long)x1 << 21) | y1; pointCounts.put(currentKey, pointCounts.getOrDefault(currentKey, 0) + 1); } return count; }}Complexity
Time
O(N * k), where N is the number of points and `k` is the target distance. For each of the N points, we perform `k+1` lookups in the hash map. Since `k` is very small (<= 100), this complexity is effectively linear, i.e., O(N).
Space
O(U), where U is the number of unique points in the input. In the worst-case scenario where all N points are unique, the space complexity is O(N).
Trade-offs
Pros
Very efficient, with a time complexity that is effectively linear in the number of points.
Handles the problem constraints with ease.
The logic is a clever application of hash maps and bitwise operations to solve a counting problem.
Cons
Requires extra space to store the hash map, which can be up to O(N) in the worst case where all points are unique.
Solutions
Solution
class Solution {public int countPairs(List<List<Integer>> coordinates, int k) { Map<List<Integer>, Integer> cnt = new HashMap<>(); int ans = 0; for (var c : coordinates) { int x2 = c.get(0), y2 = c.get(1); for (int a = 0; a <= k; ++a) { int b = k - a; int x1 = a ^ x2, y1 = b ^ y2; ans += cnt.getOrDefault(List.of(x1, y1), 0); } cnt.merge(c, 1, Integer : : sum); } return ans; }}class Solution {public: int countPairs(vector<vector<int>> &coordinates, int k) { map<pair<int, int>, int> cnt; int ans = 0; for (auto &c : coordinates) { int x2 = c[0], y2 = c[1]; for (int a = 0; a <= k; ++a) { int b = k - a; int x1 = a ^ x2, y1 = b ^ y2; ans += cnt[{x1, y1}]; } ++cnt[{x2, y2}]; } return ans; }};class Solution: def countPairs(self, coordinates: List[List[int]], k: int) -> int: cnt = Counter() ans = 0 for x2, y2 in coordinates: for a in range(k + 1): b = k - a x1, y1 = a ^ x2, b ^ y2 ans += cnt[(x1, y1)] cnt[(x2, y2)] += 1 return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.