Given an integer array arr[] of size n and an integer k, consider the absolute difference of arr[i] and arr[j] for every pair of indices i != j. Find the kth smallest value among all these pairwise differences.
Examples:Â
Input: arr[] = [1, 2, 3, 4], k = 3
Output: 1
Explanation: The pairwise differences are [1, 2, 3, 1, 2, 1]. Sorted, they become [1, 1, 1, 2, 2, 3] - the 3rd smallest is 1.Input: arr[] = [10, 10, 10, 10], k = 6
Output: 0
Explanation: Every pair of elements is identical, so all 6 pairwise differences are 0. Hence, the 6th smallest is 0.
Table of Content
[Naive Approach] Using Pairwise Difference Generation - O((n * n) log n) Time and O(n * n) Space
The idea is to explicitly generate every pairwise absolute difference abs(arr[i] - arr[j]) for all i < j, store them all in a list, sort this list, and simply return the kth element. This directly mirrors the problem statement but requires storing and sorting all n*(n-1)/2 differences, making it slow for large arrays.
Step by Step Explanation:
- Generate every pairwise difference abs(arr[i] - arr[j]) for all valid index pairs i < j.
- Store all these differences in a list.
- Sort the list of differences in ascending order.
- Return the element at index k-1 (the kth smallest).
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int kthSmallest(vector<int> &arr, int k) {
vector<int> diffs;
int n = arr.size();
// Generate every pairwise difference
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
diffs.push_back(abs(arr[i] - arr[j]));
}
}
sort(diffs.begin(), diffs.end());
return diffs[k - 1];
}
int main() {
vector<int> arr = {1, 2, 3, 4};
int k = 3;
cout << kthSmallest(arr, k) << endl;
return 0;
}
import java.util.ArrayList;
import java.util.Collections;
class GFG {
static int kthSmallest(int[] arr, int k) {
ArrayList<Integer> diffs = new ArrayList<>();
int n = arr.length;
// Generate every pairwise difference
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
diffs.add(Math.abs(arr[i] - arr[j]));
}
}
Collections.sort(diffs);
return diffs.get(k - 1);
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
int k = 3;
System.out.println(kthSmallest(arr, k));
}
}
def kthSmallest(arr, k):
diffs = []
n = len(arr)
# Generate every pairwise difference
for i in range(n):
for j in range(i + 1, n):
diffs.append(abs(arr[i] - arr[j]))
diffs.sort()
return diffs[k - 1]
arr = [1, 2, 3, 4]
k = 3
print(kthSmallest(arr, k))
using System;
using System.Collections.Generic;
class GFG {
static int kthSmallest(int[] arr, int k) {
List<int> diffs = new List<int>();
int n = arr.Length;
// Generate every pairwise difference
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
diffs.Add(Math.Abs(arr[i] - arr[j]));
}
}
diffs.Sort();
return diffs[k - 1];
}
static void Main() {
int[] arr = { 1, 2, 3, 4 };
int k = 3;
Console.WriteLine(kthSmallest(arr, k));
}
}
function kthSmallest(arr, k) {
const diffs = [];
const n = arr.length;
// Generate every pairwise difference
for (let i = 0; i < n; i++) {
for (let j = i + 1; j < n; j++) {
diffs.push(Math.abs(arr[i] - arr[j]));
}
}
diffs.sort((a, b) => a - b);
return diffs[k - 1];
}
// Driver Code
const arr = [1, 2, 3, 4];
const k = 3;
console.log(kthSmallest(arr, k));
Output
1
[Better Approach] Using Min-Heap - O((n + k) log n) Time and O(n) Space
The idea is to sort the array. After sorting, for each index i, the differences arr[j] - arr[i] (for j > i) increase as j grows - so each i generates its own naturally sorted sequence of candidates. Using a min-heap to always pop the smallest pending difference across all these sequences lets us extract differences in fully sorted order, stopping as soon as we've popped the kth one.
Step by Step Implementation:
- Sort the array.
- Push (arr[i+1] - arr[i], i, i+1) into a min-heap for every i from 0 to n-2.
- Pop the smallest difference from the heap, k times.
- After each pop (diff, i, j), if j+1 < n, push (arr[j+1] - arr[i], i, j+1) as the next candidate for that same i.
- The value popped on the kth time is the answer.
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
int kthSmallest(vector<int> &arr, int k) {
sort(arr.begin(), arr.end());
int n = arr.size();
// min-heap of {difference, i, j}
priority_queue<vector<int>, vector<vector<int>>, greater<vector<int>>> heap;
for (int i = 0; i < n - 1; i++) {
heap.push({arr[i + 1] - arr[i], i, i + 1});
}
int diff = -1;
for (int count = 0; count < k; count++) {
vector<int> top = heap.top();
heap.pop();
diff = top[0];
int i = top[1], j = top[2];
if (j + 1 < n) {
heap.push({arr[j + 1] - arr[i], i, j + 1});
}
}
return diff;
}
int main() {
vector<int> arr = {1, 2, 3, 4};
int k = 3;
cout << kthSmallest(arr, k) << endl;
return 0;
}
import java.util.Arrays;
import java.util.PriorityQueue;
class GFG {
static int kthSmallest(int[] arr, int k) {
Arrays.sort(arr);
int n = arr.length;
// min-heap of {difference, i, j}
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[0] - b[0]);
for (int i = 0; i < n - 1; i++) {
heap.add(new int[]{arr[i + 1] - arr[i], i, i + 1});
}
int diff = -1;
for (int count = 0; count < k; count++) {
int[] top = heap.poll();
diff = top[0];
int i = top[1], j = top[2];
if (j + 1 < n) {
heap.add(new int[]{arr[j + 1] - arr[i], i, j + 1});
}
}
return diff;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
int k = 3;
System.out.println(kthSmallest(arr, k));
}
}
import heapq
def kthSmallest(arr, k):
arr.sort()
n = len(arr)
# min-heap of (difference, i, j)
heap = []
for i in range(n - 1):
heapq.heappush(heap, (arr[i + 1] - arr[i], i, i + 1))
diff = -1
for _ in range(k):
diff, i, j = heapq.heappop(heap)
if j + 1 < n:
heapq.heappush(heap, (arr[j + 1] - arr[i], i, j + 1))
return diff
arr = [1, 2, 3, 4]
k = 3
print(kthSmallest(arr, k))
using System;
using System.Collections.Generic;
class GFG {
static int kthSmallest(int[] arr, int k) {
Array.Sort(arr);
int n = arr.Length;
// min-heap of (difference, i, j) using SortedSet as a substitute priority queue
SortedSet<(int diff, int i, int j)> heap = new SortedSet<(int, int, int)>();
for (int i = 0; i < n - 1; i++) {
heap.Add((arr[i + 1] - arr[i], i, i + 1));
}
int diff = -1;
for (int count = 0; count < k; count++) {
var top = heap.Min;
heap.Remove(top);
diff = top.diff;
int i = top.i, j = top.j;
if (j + 1 < n) {
heap.Add((arr[j + 1] - arr[i], i, j + 1));
}
}
return diff;
}
static void Main() {
int[] arr = { 1, 2, 3, 4 };
int k = 3;
Console.WriteLine(kthSmallest(arr, k));
}
}
class MinHeap {
constructor() {
this.heap = [];
}
push(item) {
this.heap.push(item);
let i = this.heap.length - 1;
while (i > 0) {
const parent = Math.floor((i - 1) / 2);
if (this.heap[parent][0] <= this.heap[i][0]) break;
[this.heap[parent], this.heap[i]] = [this.heap[i], this.heap[parent]];
i = parent;
}
}
pop() {
const top = this.heap[0];
const last = this.heap.pop();
if (this.heap.length > 0) {
this.heap[0] = last;
let i = 0;
while (true) {
let left = 2 * i + 1, right = 2 * i + 2, smallest = i;
if (left < this.heap.length && this.heap[left][0] < this.heap[smallest][0]) smallest = left;
if (right < this.heap.length && this.heap[right][0] < this.heap[smallest][0]) smallest = right;
if (smallest === i) break;
[this.heap[i], this.heap[smallest]] = [this.heap[smallest], this.heap[i]];
i = smallest;
}
}
return top;
}
}
function kthSmallest(arr, k) {
arr.sort((a, b) => a - b);
const n = arr.length;
// min-heap of [difference, i, j]
const heap = new MinHeap();
for (let i = 0; i < n - 1; i++) {
heap.push([arr[i + 1] - arr[i], i, i + 1]);
}
let diff = -1;
for (let count = 0; count < k; count++) {
const top = heap.pop();
diff = top[0];
const i = top[1], j = top[2];
if (j + 1 < n) {
heap.push([arr[j + 1] - arr[i], i, j + 1]);
}
}
return diff;
}
// Driver Code
const arr = [1, 2, 3, 4];
const k = 3;
console.log(kthSmallest(arr, k));
Output
1
[Expected Approach] Using Binary Search on Answer - O(n log n) Time and O(1) Space
The idea is to binary search on the answer itself - the value of the kth smallest difference - rather than generating every pairwise difference explicitly. For a candidate difference mid, we can count how many pairs have difference âĪ mid in O(n) using two pointers on the sorted array. If that count is at least k, the answer is mid or smaller; otherwise it must be larger. This narrows the search space by half each time instead of enumerating all pairs.
Step by Step Implementation:
- Sort the array.
- Binary search on the difference value, between 0 and max(arr) - min(arr).
- For each candidate mid, use two pointers to count how many pairs have difference âĪ mid.
- If that count is âĨ k, move the search range down (the answer is âĪ mid); otherwise move it up.
- Once the search range narrows to a single value, that value is the kth smallest difference.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int kthSmallest(vector<int> &arr, int k) {
sort(arr.begin(), arr.end());
int n = arr.size();
int lo = 0, hi = arr[n - 1] - arr[0];
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
// Count pairs with difference <= mid using two pointers
long long count = 0;
int j = 0;
for (int i = 0; i < n; i++) {
while (j < n && arr[j] - arr[i] <= mid) j++;
count += (j - i - 1);
}
if (count >= k) hi = mid;
else lo = mid + 1;
}
return lo;
}
int main() {
vector<int> arr = {1, 2, 3, 4};
int k = 3;
cout << kthSmallest(arr, k) << endl;
return 0;
}
import java.util.Arrays;
class GFG {
static int kthSmallest(int[] arr, int k) {
Arrays.sort(arr);
int n = arr.length;
int lo = 0, hi = arr[n - 1] - arr[0];
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
// Count pairs with difference <= mid using two pointers
long count = 0;
int j = 0;
for (int i = 0; i < n; i++) {
while (j < n && arr[j] - arr[i] <= mid) j++;
count += (j - i - 1);
}
if (count >= k) hi = mid;
else lo = mid + 1;
}
return lo;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
int k = 3;
System.out.println(kthSmallest(arr, k));
}
}
def kthSmallest(arr, k):
arr.sort()
n = len(arr)
lo, hi = 0, arr[n - 1] - arr[0]
while lo < hi:
mid = lo + (hi - lo) // 2
# Count pairs with difference <= mid using two pointers
count = 0
j = 0
for i in range(n):
while j < n and arr[j] - arr[i] <= mid:
j += 1
count += (j - i - 1)
if count >= k:
hi = mid
else:
lo = mid + 1
return lo
arr = [1, 2, 3, 4]
k = 3
print(kthSmallest(arr, k))
using System;
class GFG {
static int kthSmallest(int[] arr, int k) {
Array.Sort(arr);
int n = arr.Length;
int lo = 0, hi = arr[n - 1] - arr[0];
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
// Count pairs with difference <= mid using two pointers
long count = 0;
int j = 0;
for (int i = 0; i < n; i++) {
while (j < n && arr[j] - arr[i] <= mid) j++;
count += (j - i - 1);
}
if (count >= k) hi = mid;
else lo = mid + 1;
}
return lo;
}
static void Main() {
int[] arr = { 1, 2, 3, 4 };
int k = 3;
Console.WriteLine(kthSmallest(arr, k));
}
}
function kthSmallest(arr, k) {
arr.sort((a, b) => a - b);
const n = arr.length;
let lo = 0, hi = arr[n - 1] - arr[0];
while (lo < hi) {
const mid = lo + Math.floor((hi - lo) / 2);
// Count pairs with difference <= mid using two pointers
let count = 0;
let j = 0;
for (let i = 0; i < n; i++) {
while (j < n && arr[j] - arr[i] <= mid) j++;
count += (j - i - 1);
}
if (count >= k) hi = mid;
else lo = mid + 1;
}
return lo;
}
// Driver Code
const arr = [1, 2, 3, 4];
const k = 3;
console.log(kthSmallest(arr, k));
Output
1