#3520
Medium Algorithms Minimum threshold for inversion pairs count
Array Binary Search Binary Indexed Tree Segment Tree
54.7% acceptance
Mar 31, 2026
3
1
You are given an array of integers nums and an integer k.
An inversion pair with a threshold x is defined as a pair of indices (i, j) such that:
i < j
nums[i] > nums[j]
The difference between the two numbers is at most x (i.e. nums[i] - nums[j] <= x).
Your task is to determine the minimum integer min_threshold such that there are at least k inversion pairs with threshold min_threshold.
If no such integer exists, return -1.
Solution
Rust
Time O(n log n)
Space O(n)
impl Solution {
pub fn min_threshold(nums: Vec<i32>, k: i32) -> i32 {
// Binary search on the threshold x.
// For a given x, count inversion pairs (i<j) with nums[i]>nums[j] and nums[i]-nums[j]<=x.
// That means: nums[j] < nums[i] <= nums[j] + x.
//
// We need at least k such pairs. Binary search for minimum x.
// For counting: use a modified merge sort or BIT.
//
// For a given threshold x, sweep from left to right. For each j, count how many
// previous i have nums[i] in range (nums[j], nums[j]+x].
// Use a BIT indexed by value. But values up to 10^9, so coordinate compress.
let n = nums.len();
if n <= 1 { return -1; }
// Coordinate compress
let mut sorted_vals: Vec<i32> = nums.clone();
sorted_vals.sort();
sorted_vals.dedup();
let compress = |v: i32| -> usize {
sorted_vals.binary_search(&v).unwrap() + 1 // 1-indexed
};
let m = sorted_vals.len();
// BIT (Fenwick tree)
struct BIT {
tree: Vec<i64>,
n: usize,
}
impl BIT {
fn new(n: usize) -> Self { BIT { tree: vec![0; n + 1], n } }
fn update(&mut self, mut i: usize, val: i64) {
while i <= self.n { self.tree[i] += val; i += i & i.wrapping_neg(); }
}
fn query(&self, mut i: usize) -> i64 {
let mut s = 0i64;
while i > 0 { s += self.tree[i]; i -= i & i.wrapping_neg(); }
s
}
fn range_query(&self, l: usize, r: usize) -> i64 {
if l > r { return 0; }
self.query(r) - if l > 0 { self.query(l - 1) } else { 0 }
}
}
let count_pairs = |threshold: i64| -> i64 {
let mut bit = BIT::new(m);
let mut cnt = 0i64;
for j in 0..n {
// Count previous elements in range (nums[j], nums[j] + threshold]
let lo = nums[j] as i64 + 1;
let hi = nums[j] as i64 + threshold;
// Find compressed indices for lo and hi
let l_idx = sorted_vals.partition_point(|&v| (v as i64) < lo) + 1; // 1-indexed
let r_idx = sorted_vals.partition_point(|&v| (v as i64) <= hi); // 1-indexed (inclusive)
if l_idx <= r_idx && r_idx >= 1 {
cnt += bit.range_query(l_idx, r_idx);
}
let ci = compress(nums[j]);
bit.update(ci, 1);
}
cnt
};
// Binary search on threshold
// threshold range: 0 to max_diff
// At threshold = 0: count pairs where nums[i] > nums[j] and nums[i]-nums[j] <= 0 -> 0 pairs
// We need the minimum threshold where count >= k
// Max possible threshold: max(nums) - min(nums)
let max_val = *nums.iter().max().unwrap() as i64;
let min_val = *nums.iter().min().unwrap() as i64;
let max_threshold = max_val - min_val;
// First check if even with max threshold we can get k pairs
// Max threshold = all inversion pairs
let total_inversions = count_pairs(max_threshold);
if total_inversions < k as i64 {
return -1;
}
let mut lo = 0i64;
let mut hi = max_threshold;
while lo < hi {
let mid = lo + (hi - lo) / 2;
if count_pairs(mid) >= k as i64 {
hi = mid;
} else {
lo = mid + 1;
}
}
lo as i32
}
}