Open azl397985856 opened 3 years ago
class Solution
{
public:
int smallestDistancePair(vector<int> &nums, int k)
{
// The search space for the pair distance is [0, max{nums} - min{nums}]
// the helper subroutine takes in a distance parameter and returns the number of pairs that is <= that parameter
// the array needs to be sorted
std::sort(nums.begin(), nums.end());
int left{ 0 };
int right = nums.back() - nums.front();
while (left <= right) {
int mid = left + (right - left) / 2;
int nPairsBeforeMid = countDistancePairs(nums, mid);
if (nPairsBeforeMid == k) {
// Too many pairs, shrink the right side
right = mid - 1;
} else if (nPairsBeforeMid > k) {
right = mid - 1;
} else if (nPairsBeforeMid < k) {
left = mid + 1;
}
}
return left;
}
private:
/*
* @return the number of distance pairs that is <= upperBound
*/
int countDistancePairs(vector<int> &nums, int upperBound)
{
// two-pointer sliding window problem
int fast{ 0 };
int slow{ 0 };
int res{ 0 };
while (fast < nums.size()) {
// fast sets the right boundary of the window
// shrink the window if needed
// the next j doesn't have to restart the slow pointer from 0
// because if nums[j] - nums[slow] > upperBound, then nums[j+1] - nums[i] > upperBound for i <= slow
while (nums[fast] - nums[slow] > upperBound) slow++;
res += fast - slow;
fast++;
}
return res;
}
};
https://binarysearch.com/problems/Kth-Pair-Distance
k
pairs' absolute diff are <= target.import java.util.*;
class Solution {
public int solve(int[] nums, int k) {
Arrays.sort(nums);
int start = 0;
int end = nums[nums.length - 1] - nums[0];
while(start + 1 < end){
int mid = start + (end - start) / 2;
if(count(nums, mid) < k){
start = mid;
}else if(count(nums, mid) > k){
end = mid;
}else{
start = mid;// if there are k pairs' diff <= mid, mid may be the k - 1th smallest, need to try whether there is a bigger mid
}
}
return count(nums, start) <= k? end: start; // if there are k pairs' diff <= start, start may be the k - 1th smallest, then end is the kth smallest
}
// count how many pairs' diff is <= mid
private long count(int[] nums, int mid){
long result = 0; // int would cause overflow, because n <= 100,000, result is greater than max int
int left = 0;
for(int right = 1; right < nums.length; right++){
while(nums[right] - nums[left] > mid){
left++;
}
if(nums[right] - nums[left] <= mid){
result += right - left;
}
}
return result;
}
}
二分法找可行的diff, 且该diff的对数是少于k 双指针寻找对应diff的pair数量
最后判断leftdiff 的数量必须大于等于k(多对pair有相同的leftdiff), 否则return rightdiff
class Solution {
public int smallestDistancePair(int[] nums, int k) {
Arrays.sort(nums);
int left = 0;
int right = nums[nums.length - 1] - nums[0];
while (left + 1 < right) {
int midDiff = left + (right - left) / 2;
if (getDiffCnt(midDiff, nums) >= k) {
right = midDiff;
} else {
left = midDiff;
}
}
//判断leftDiff的数量是大于等于第k对
if (getDiffCnt(left, nums) >= k) {
return left;
}
return right;
}
private int getDiffCnt(int diff, int[] nums) {
int i = 0;
int cnt = 0;
int j = 1;
while (j < nums.length) {
while (nums[j] - nums[i] > diff) {
i++;
}
cnt += j - i;
j++;
}
return cnt;
}
}
Time/Space : O(NlogN), O(1)
Go Code:
func getCount(nums []int, mid int) int {
var res int
for i := 0; i < len(nums); i++ {
j := 0
for nums[i]-nums[j] > mid {
j++
}
res += i - j
}
return res
}
func solve(nums []int, k int) int {
sort.Ints(nums)
left, right := 0, nums[len(nums)-1]-nums[0]
for left <= right {
mid := (right-left)/2 + left
if getCount(nums, mid) < k {
left = mid + 1
} else {
right = mid - 1
}
}
return left
}
复杂度分析
令 n 为数组长度。
class Solution:
def solve(self, A, k):
A.sort()
def count_not_greater(diff):
i = ans = 0
for j in range(1, len(A)):
while A[j] - A[i] > diff:
i += 1
ans += j - i
return ans
l, r = 0, A[-1] - A[0]
k += 1
while l <= r:
mid = (l + r) // 2
if count_not_greater(mid) >= k:
r = mid - 1
else:
l = mid + 1
return l
参考题解思路
class Solution {
solve(nums, k) {
nums = nums.sort((a, b) => a - b)
let left = 0, right = nums[nums.length - 1] - nums[0], mid
while (left <= right) {
mid = left + ((right - left) >>> 1)
if (this.ok(nums, mid) > k) right = mid - 1
else left = mid + 1
}
return left
}
ok(nums, mid) {
let res = 0, i = 0
for (let j = 1; j < nums.length; j++) {
while ((nums[j] - nums[i]) > mid) i ++
res += j - i
}
return res
}
}
时间复杂度:O(logN)
空间复杂度:O(1)
思路:二分 排序
class Solution {
public int solve(int[] nums, int k) {
Arrays.sort(nums);
int n = nums.length;
int left = 0, right = nums[n - 1] - nums[0];
while(left <= right){
int mid = left + (right - left) / 2;
int cnt = 0,start = 0;
for(int i = 0; i < n; ++i){
while(start < n && nums[i] - nums[start] < mid) ++start;
cnt += i - start;
}
if(cnt < k){
left = mid + 1;
}else{
right = mid - 1;
}
}
return left;
}
}
时间复杂度:O(NlogN) 空间复杂度:O(1)
思路
暴力枚举所有解,然后排序找出第k个(时间超时
代码
public Integer Distance_(int[] ints,int k){
List<Integer> ret = new ArrayList<>();
for (int i = 0; i < ints.length; i++) {
for (int j = i + 1; j < ints.length; j++) {
ret.add(Math.abs(ints[i] - ints[j]));
}
}
ret.sort(Integer::compareTo);
return ret.get(k - 1);
}
复杂度
时间复杂度:O(N^2)
空间复杂度:O(N)
思路
二分+滑动窗口 copy大佬的
代码
public int solve(int[] nums, int k) {
Arrays.sort(nums);
int absMin = 0;
int absMax = nums[nums.length-1] - nums[0];
while (absMin <= absMax) {
int absMid = (absMin + absMax) / 2;
System.out.println("mid: " + absMid);
if (count(nums, absMid) <= k) {
absMin = absMid + 1;
} else {
absMax = absMid - 1;
}
}
return absMin;
}
private long count(int[] nums, int targetDiff) {
long counter = 0;
int l = 0;
for (int r=1; r<nums.length; r++) {
while (nums[r] - nums[l] > targetDiff) {
l++;
}
counter += r - l;
}
return counter;
}
复杂度
时间复杂度:O(NlogN)
空间复杂度:O(1)
对值进行二分。对于每一个mid值,遍历数组,计算有多少个pair的绝对值<=mid.
class Solution {
public int solve(int[] nums, int k) {
Arrays.sort(nums);
int start = 0;
int end = nums[nums.length - 1] - nums[0];
k += 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (countNoGreaterThan(nums, mid) >= (long) k) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return start;
}
public long countNoGreaterThan(int[] nums, int x) {
long count = 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
while (nums[j] - nums[i] > x) {
i++;
}
count += j - i;
}
return count;
}
}
时间:O(nlogn)
空间:O(1)
class Solution {
public int smallestDistancePair(int[] nums, int k) {
Arrays.sort(nums);
int len = nums.length;
int left = 0;
int right = nums[len - 1] - nums[0];
while (left <= right) {
int mid = (left + right) / 2;
if (isCounted(nums, mid) < k) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
public int isCounted(int[] nums, int distance) {
int l = 0;
int count = 0;
for (int r = 0; r < nums.length; r ++) {
while (nums[r] - nums[l] > distance) {
l ++;
}
count += r - l;
}
return count;
}
}
Explanation
Code
class Solution:
def solve(self, nums, k):
nums.sort()
def helper(target):
count = 0
prev = 0
for i in range(1, len(nums)):
while nums[i] - nums[prev] > target:
prev += 1
count += i - prev
return count
start, end = 0, nums[-1] - nums[0]
while start <= end:
mid = start + (end - start) // 2
if helper(mid) > k:
end = mid - 1
else:
start = mid + 1
return start
Complexity
O(NlogN)
O(1)
long long count(vector<int>& nums, int d)
{
int i = 0;
long long res = 0;
for(int j = 1; j < nums.size(); j++)
{
while((nums[j] - nums[i]) > d)
i++;
res += (j - i);
}
return res;
}
int solve(vector<int>& nums, int k)
{
sort(nums.begin(), nums.end());
int l = 0, r = nums[nums.size() - 1] - nums[0];
k++;
while(l <= r)
{
int mid = l + (r - l ) / 2;
if (count(nums, mid) >= k)
r = mid - 1;
else
l = mid + 1;
}
return l;
}
class Solution:
def solve(self, A, k):
A.sort()
def count_not_greater(diff):
i = ans = 0
for j in range(1, len(A)):
while A[j] - A[i] > diff:
i += 1
ans += j - i
return ans
l, r = 0, A[-1] - A[0]
k += 1 # zero based -> one based
while l <= r:
mid = (l + r) // 2
if count_not_greater(mid) >= k:
r = mid - 1
else:
l = mid + 1
return l
二分取值空间
import java.util.*;
class Solution {
public int solve(int[] nums, int k) {
Arrays.sort(nums);
int len = nums.length;
int l = 0, r = nums[len - 1] - nums[0];
k += 1;
while (l <= r) {
int mid = (l + r) >>> 1;
if (count(nums, mid) >= k) {
r = mid - 1;
} else {
l = mid + 1;
}
}
return l;
}
private long count(int[] nums, int mid) {
long ans = 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
while (nums[j] - nums[i] > mid) {
i++;
}
ans += j -i;
}
return ans;
}
}
二分
import java.util.*;
class Solution {
public int solve(int[] nums, int k) {
k = k+1;
Arrays.sort(nums);
int l = 0,r = nums[nums.length-1]-nums[0];
while(l<=r){
int mid = l + (r - l) / 2;
if(isok(mid,nums) >= k) r = mid - 1;
else l = mid + 1;
}
return l;
}
public long isok(int x, int[] nums){
long ans = 0;
int i=0;
for(int j =1;j<nums.length;j++){
while(nums[j]-nums[i] > x){
i++;
}
ans +=(j-i);
}
return ans;
}
}
时间复杂度:O(nlogn) 空间复杂度:O(1)
统计个数,需要排序,用k比较个数大小
class Solution {
public int KthPairDistance(int[] nums,int k) {
k++;
Arrays.sort(nums);
int l= 0,r= nums[nums.length-1]-nums[0],ans= 0;
while (l<=r){
int mid= (r+l)/2;
if(distance(nums,k,mid)){
l = mid+1;
}else {
ans=mid;
r = mid-1;
}
}
return ans;
}
public boolean distance(int[] nums,int k,int mid) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
for (int j = i+1; j < nums.length; j++) {
if(nums[j]-nums[i]<=mid){
sum++;
}else {
break;
}
}
}
return k > sum;
}
}
时间复杂度:O(nlogn) 空间复杂度:O(1)
def smallestDistancePair(self, nums: List[int], k: int) -> int:
nums.sort()
l, r = 0, nums[-1] - nums[0]
def count_pairs(mid):
count = left = 0
for i in range(len(nums)):
while nums[i] - nums[left] > mid:
left += 1
count += i - left
return count >= k
while l < r:
mid = (l + r)//2
if count_pairs(mid):
r= mid
else:
l = mid + 1
return l
Time: O(nlogn)
Space: O(1)
import java.util.*;
class Solution {
public int solve(int[] nums, int k) {
k += 1;
Arrays.sort(nums);
int l = 0, r = nums[nums.length - 1] - nums[0];
while( l < r) {
int mid = (l + r) >> 1;
// 看差值mid 之前有多少更小的差值数字 加起看是否大于等于k 如果大于等于k了 说明mid取大了
boolean ok = isK(mid, k, nums);
// find a value
if(ok){
r = mid;
} else {
l = mid + 1;
}
}
return l;
}
private boolean moreThanOrEqualsK(int mid, int k, int[] numsSorted) {
int pairsDiffGreaterThanKCnt = 0;
for(int l = 0, r = 0; l < numsSorted.length; l++) {
// 求差值要小于等于 mid的有多少对数字 如 1 2 3 4 第一小的是1
// 差值 4, 3, 2,2, 1 中小于等于3的有4个 重复的也算
while((r < numsSorted.length) && (numsSorted[r] - numsSorted[l]) <= mid) {r ++;};
if( (pairsDiffGreaterThanKCnt += (r-l-1) ) >= k) return true;
}
return false;
}
}
暴力解N**2 会超时。
二分其实就是找到一个mid,然后去排序好的队列里找到pair(a,b) b-a <= target, 那么[a,b] 里每一个点都可以组成合理的pair。 但是这里具体哪几个数字组成pair 不重要,只需要一个count 来计算 每取一个mid,这个数组中有多少对 小于等于 mid, 然后用count再跟k比较判断是left/right变动。
class Solution:
def solve(self, nums, k):
nums.sort()
left,right = 0, nums[-1]
while left < right:
mid = left + (right-left)//2
if self.valid(nums,mid) > k:
right= mid
else:
left = mid +1
return left
def valid(self,nums,target):
# 求出比pair(a,b)比mid小的值有多少个 => 每一个点,找到后面的一个点pair(a,b) <= target: 说明[a,b] 之间每一个点都可以凑成一个pair
count = 0
l = 0
# 类似双指针思想来计算count
for r in range(len(nums)):
while nums[r] - nums[l] > target:
l += 1
count += r - l
return count
Time complexity: O(N logN) Space complexity: O(1)
二分,通过一个helper来计算given difference,有多少pair的difference小于等于这个值。如果对数大于等于k,那么我们可以缩小范围到左边(移动r),因为超过了需要的范围,如果对数小于k,我们移动l往右边压缩范围。
// helper method that returns the number of absolute values(pair) <= n
long long helper(vector<int>& nums, int n) {
long long ans = 0;
int i = 0;
// 2 pointers
for (int j = 1; j < nums.size(); ++j) {
// diff > n means that we need to discard this pair and want to look for smaller ones
while (nums[j] - nums[i] > n) {
i++;
}
ans += (j - i);
}
return ans;
}
// find a difference x, making k absolute values smaller/equal to the number of x
int solve(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int l = 0, r = nums.back() - nums[0]; // answer exists in [0, diff(max of nums, min of nums)]
k++; // turn into 0-indexed
while (l <= r) {
int mid = l + (r - l) / 2;
if (helper(nums, mid) >= k) {
r = mid - 1;
} else {
l = mid + 1;
}
}
return l;
}
class Solution:
def solve(self, A, k):
A.sort()
def count_not_greater(diff):
i = ans = 0
for j in range(1, len(A)):
while A[j] - A[i] > diff:
i += 1
ans += j - i
return ans
l, r = 0, A[-1] - A[0]
k += 1
while l <= r:
mid = (l + r) // 2
if count_not_greater(mid) >= k:
r = mid - 1
else:
l = mid + 1
return l
class Solution {
solve(nums, k) {
const n = nums.length;
nums.sort((a, b) => a - b);
let left = 0;
let right = nums[n - 1] - nums[0]; // max diff
k += 1; // zero based -> one based
while (left < right) {
const mid = left + ~~((right - left) / 2);
if (this.countNotGreater(nums, mid) >= k) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
countNotGreater(nums, diff) {
let count = 0;
let left = 0;
for (let i = 1; i < nums.length; ++i) {
while (nums[i] - nums[left] > diff) {
left += 1;
}
count += i - left;
}
return count;
}
}
class Solution:
def solve(self, nums, k):
nums.sort()
def count(diff):
i = ans = 0
for j in range(1, len(nums)):
while nums[j] - nums[i] > diff:
i += 1
ans += j - i
return ans
left, right = 0, nums[-1] - nums[0]
k += 1
while left <= right:
mid = (left + right) // 2
if count(mid) >= k:
right = mid - 1
else:
left = mid + 1
return left
class Solution {
public int solve(int[] nums, int k) {
k++;
if(k < 0) return -1;
Arrays.sort(nums);
//配合二分
int left = 0, right = nums[nums.length - 1] - nums[0];
while (left < right) {
int mid = left + (right - left) / 2;
if(countGre(mid, nums) >= k) {
right = mid;
}else {
left = mid + 1;
}
}
return left;
}
public long countGre(int diff, int[] nums) {
int i = 0;
//使用long类型防止溢出
long ans = 0;
for (int j = 1; j < nums.length; j++) {
while (nums[j] - nums[i] > diff) {
i++;
}
ans += j - i;
}
return ans;
}
}
class Solution {
public:
bool check(vector<int> a, int k, int x) {
//printf("mid = %d\n", x);
int res = 0;
int index = 1;
for(int i = 0; i < a.size(); i++) {
int j = index;
while(j < a.size() && a[j] <= a[i] + x) {
j++;
}
//printf("out, j = %d\n", j);
res += j - i - 1;
index = j;
//printf("res = %d, index = %d\n", res, index);
}
//res >= k ? printf("Return True\n\n") : printf("Return False\n\n");
return res >= k;
}
int smallestDistancePair(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int l = 0, r = int(nums.back()) - nums[0];
while(l <= r) {
int mid = l + ((r - l) >> 1);
if(check(nums, k, mid)) {
r = mid - 1;
} else {
l = mid + 1;
}
}
return l;
}
};
/**
* @param {number[]} nums
* @param {number} k
* @return {number}
*/
var smallestDistancePair = function (nums, k) {
nums.sort((a, b) => a - b)
let len = nums.length
//二分法的左右取距离对的最小和最大值 [0,nums[len-1]-nums[0]]
let left = 0, right = nums[len - 1] - nums[0]
while (left <= right) {
let mid = Math.floor((left + right) / 2)
let cur = 0; //小于mid的数量
let start = 0;// 双指针中的左指针,属于循环中的第一个值
// 以 i 为终点求距离差小于 mid 的数量
for (let i = 1; i < len; i++) {
while (nums[i] - nums[start] > mid) {
start++
}
cur += i - start
}
if (cur < k) {
left = mid + 1
}else{
right = mid - 1
}
}
return left
};
https://binarysearch.com/problems/Kth-Pair-Distance
思路:之前看了讲义思路, 动态求极值,求第k大,小于等于diff的值恰好有k个
class Solution:
def solve(self, nums, k):
nums.sort()
def count_not_greater(diff):
i = ans = 0
for j in range(1, len(nums)):
while nums[j] - nums[i] > diff:
i += 1
ans += j - i
return ans
l, r = 0, max(nums) - min(nums)
k +=1
while l <= r:
mid = (l + r) >> 1
if count_not_greater(mid)>=k:
# 收缩右边界# 搜索区间变为 [left, mid - 1]
r = mid - 1;
else:# 搜索区间变为 [mid+1, right]
l = mid + 1
return l
时间复杂度:
时间复杂度:O(nlogn )
空间复杂度:O(n) 排序的空间消耗 。
class Solution {
public int solve(int[] nums, int k) {
k++;
if(k < 0) return -1;
Arrays.sort(nums);
//配合二分
int left = 0, right = nums[nums.length - 1] - nums[0];
while (left < right) {
int mid = left + (right - left) / 2;
if(countGre(mid, nums) >= k) {
right = mid;
}else {
left = mid + 1;
}
}
return left;
}
public long countGre(int diff, int[] nums) {
int i = 0;
//使用long类型防止溢出
long ans = 0;
for (int j = 1; j < nums.length; j++) {
while (nums[j] - nums[i] > diff) {
i++;
}
ans += j - i;
}
return ans;
}
}
/**
@return {number} */ var smallestDistancePair = function (nums, k) { nums.sort((a, b) => a - b) let len = nums.length //二分法的左右取距离对的最小和最大值 [0,nums[len-1]-nums[0]] let left = 0, right = nums[len - 1] - nums[0] while (left <= right) { let mid = Math.floor((left + right) / 2) let cur = 0; //小于mid的数量 let start = 0;// 双指针中的左指针,属于循环中的第一个值 // 以 i 为终点求距离差小于 mid 的数量 for (let i = 1; i < len; i++) { while (nums[i] - nums[start] > mid) { start++ } cur += i - start } if (cur < k) { left = mid + 1 }else{ right = mid - 1 }
} return left };
class Solution:
def solve(self, nums, k):
nums.sort()
k += 1
left, right = 0, nums[-1] - nums[0]
while (left < right):
mid = (left + right) >> 1
if countPairs(mid) >= k:
right = mid
else:
left = mid + 1
return left
def countPairs(diff):
i = 0
ans = 0
for j in range(1, len(nums)):
while (nums[j] - nums[i] > diff):
i += 1
ans += j - i
return ans
class Solution {
public int smallestDistancePair(int[] nums, int k) {
Arrays.sort(nums);
int n = nums.length, low = 0, hi = nums[n-1] - nums[0];
while (low < hi) {
int cnt = 0, j = 0, mid = (low + hi)/2;
for (int i = 0; i < n; ++i) {
while (j < n && nums[j] - nums[i] <= mid) ++j;
cnt += j - i-1;
}
if (cnt >= k)
hi = mid;
else low = mid + 1;
}
return low;
}
}
先排序数组
二分搜索的范围是 [0, nums[-1] - nums[0]], 即 distance 可能的 最大和最小值
如果 distance 小于等于 mid 的 pair 数量 比 k 小, 那么搜索 右半区间, l = mid + 1
如果 distance 小于等于 mid 的 pair 数量 大于等于 k, 那么搜索 左半区间, r = mid - 1
最后返回 l
用双指针法计算 当 nums 中 小于等于 mid 的 pair 数量
遍历 j in [1, length), 如果 nums[j] - nums[i] > mid, i += 1, 知道 nums[j] - nums[i] ≤ mid,
此时 count += j-i , 因为 是 sorted list, 所以如果 i 满足条件, 那么 [i, j) 直接到数都比 nums[i] 大, 所以也都符合条件, 加入 count
下一个 j 也可以直接从 i 开始, 因为 i 之前的数都比 i 小, 所以 nums[j] - nums[i] 肯定会更大, 就会不符合条件
class Solution:
def smallestDistancePair(self, nums: List[int], k: int) -> int:
nums.sort()
length = len(nums)
# count the number of pairs that's less than equal to mid
def less_than_equal(mid):
i = 0
count = 0
for j in range(1, length):
while i < j and nums[j] - nums[i] > mid:
i += 1
count += j - i
return count
l, r = 0, nums[-1] - nums[0]
while l <= r:
mid = (l+r) >> 1
if less_than_equal(mid) < k:
l = mid + 1
else:
r = mid - 1
return l
n 为 数组长度, m 为 最大距离 nums[-1] - nums[0]
时间复杂度: O(nlogn + nlogm) 排序的时间复杂度是 O(nlogn), 二分时间复杂度 O(logw), 统计小于 mid 双指针时间复杂度 O(n)
空间转发的: O(n) sort 的时间复杂度
import java.util.*;
class Solution { public int solve(int[] nums, int k) { k++; Arrays.sort(nums); int lhs = 0; int rhs = nums[nums.length - 1] - nums[0]; while (lhs < rhs) { int mid = (lhs + rhs) / 2; long amt = 0; int leftp = 0; for (int i = 1; i < nums.length; i++) { while (nums[i] - nums[leftp] > mid) leftp++; amt += i - leftp; } if (amt >= k) rhs = mid; else lhs = mid + 1; } return lhs;
}
}
二分法
``
public class Solution extends VersionControl {
public int solve(int[] nums, int k) {
Arrays.sort(nums);
int start = 0;
int end = nums[nums.length - 1] - nums[0];
k += 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (countNoGreaterThan(nums, mid) >= (long) k) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return start;
}
public long countNoGreaterThan(int[] nums, int x) {
long count = 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
while (nums[j] - nums[i] > x) {
i++;
}
count += j - i;
}
return count;
}
}
时间复杂度:O(nlogn)
空间复杂度:O(1)
二分 使中间值逐渐逼近 kth 大 target
bool check(vector<int>& nums, int diff, int k) {
const int N = nums.size();
long count = 0;
int i = 0, j = 0;
while (i < N || j < N) {
while (j < N && nums[j] - nums[i] <= diff) j++;
count += j - i - 1;
i++;
}
return count >= k;
};
int solve(vector<int>& nums, int k) {
const int N = nums.size();
sort(nums.begin(), nums.end());
k += 1;
int left = 0, right = nums[N - 1] - nums[0];
while (left < right) {
int mid = left + (right - left) / 2;
if (check(nums, mid, k))
right = mid;
else
left = mid + 1;
}
return left;
}
```cpp
function solve(nums, k) {
nums.sort((a, b) => a - b)
let l = 0,
r = nums[nums.length - 1] - nums[0],
mid
while (l <= r) {
mid = (l + r) >> 1
if (getCount(nums, mid) < k) {
l = mid + 1
} else {
r = mid - 1
}
}
return l
}
function getCount(nums, distance) {
let l = 0,
count = 0
for (let i = 0; i < nums.length; i++) {
while (nums[i] - nums[l] > distance) {
l++
}
count += i - l
}
return count
}
// 10-20 cpp 二分+双指针
long long help (vector<int>& nums, int mid) {
int i = 0;
long long cnt = 0;
for (int j = 1; j < nums.size(); j++) {
while(nums[j] - nums[i] > mid) ++i;
cnt += (j - i); // 记录<=d的个数
}
return cnt;
}
int solve(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int n = nums.size();
int l = 0, r = nums[n-1] - nums[0];
while (l <= r) {
int mid = l + (r -l) / 2;
if (help(nums, mid) > k) r = mid - 1;
else l = mid + 1;
}
return l;
}
class Solution:
def solve(self, A, k):
A.sort()
def count_not_greater(diff):
i = ans = 0
for j in range(1, len(A)):
while A[j] - A[i] > diff:
i += 1
ans += j - i
return ans
l, r = 0, A[-1] - A[0]
k += 1 # zero based -> one based
while l <= r:
mid = (l + r) // 2
if count_not_greater(mid) >= k:
r = mid - 1
else:
l = mid + 1
return l
long findpairs(vector<int>& nums, int val){
int N = nums.size();
long count = 0;
int i=0, j=0;
while(i<N || j<N){
while(j<N && nums[j]-nums[i]<= val) j++;
count += j-i-1;
i++;
}
return count;
}
int solve(vector<int>& nums, int k) {
sort(nums.begin(), nums.end());
int n = nums.size();
k+=1;
int start=0;
int end = nums[n-1] - nums[0];
while(start<=end){
int mid = start + (end -start)/2;
if(findpairs(nums, mid)>=k){
end = mid-1;
}else{
start = mid+1;
}
}
return start;
}
Time:O(logn) Space:O(1)
function solve(nums,k){
nums.sort();
let l=0,r=nums[nums.length-1]-nums[0]
function find(mid){
let ans=0,i=0;
for (let j=1; j<nums.length; j++){
while (nums[j] - nums[i] > mid){
i += 1
}
ans += j - i
}
console.log(ans)
return ans
}
while(l<=r){
let mid=l+((r-l)>>1)
if(find(mid)>=k){
r=mid-1
}else{
l=mid+1
}
}
return l
}
class Solution:
def solve(self, A, k):
A.sort()
def count_not_greater(diff):
i = ans = 0
for j in range(1, len(A)):
while A[j] - A[i] > diff:
i += 1
ans += j - i
return ans
l, r = 0, A[-1] - A[0]
k += 1 # zero based -> one based
while l <= r:
mid = (l + r) // 2
if count_not_greater(mid) >= k:
r = mid - 1
else:
l = mid + 1
return l
思路 直接线求距离,然后排序后直接得到第k个距离,但是此方法超时了
int solve(vector<int>& nums, int k) {
int n = nums.size();
std::vector<int> results;
for (int i = 0; i < n-1;i++)
{
for (int j = i + 1; j < n;j++)
{
int d = nums[i] - nums[j];
results.push_back(abs(d));
}
}
sort(results.begin(), results.end());
return results[k];
}
复杂度分析 时间复杂度:O(n*n) 空间复杂度:O(n)
因为超时,所以不能直接使用暴力搜索,需要使用二分法,需要先对数组拍需,查找第k小距离
title: "Day 41 822. Kth-Pair-Distance" date: 2021-10-20T20:22:16+08:00 tags: ["Leetcode", "c++", "Binary Search"] categories: ["91-day-algorithm"] draft: true
Given a list of integers nums and an integer k, return the k-th (0-indexed) smallest abs(x - y) for every pair of elements (x, y) in nums. Note that (x, y) and (y, x) are considered the same pair.
Constraints
n ≤ 100,000 where n is the length of nums
Example 1
Input
nums = [1, 5, 3, 2]
k = 3
Output
2
Explanation
Here are all the pair distances:
abs(1 - 5) = 4
abs(1 - 3) = 2
abs(1 - 2) = 1
abs(5 - 3) = 2
abs(5 - 2) = 3
abs(3 - 2) = 1
Sorted in ascending order we have [1, 1, 2, 2, 3, 4].
- 1、题目为求数组排序之后第 k 大的距离,首先排序数组,最大的距离即为数组头与尾值之差, 最小的距离当然为0,在此范围内去找寻一个合理的值即可。
- 2、使用二分法,每次取 mid = l + (r - l) / 2,可以减少查找的时间复杂度,不然使用计数的话,时间复杂度在O($n^2$)。
- 3、本题目也可以使用数学的思想去考虑,所有的距离对为一共有$n(n-1)$,所以只要大于mid距离的对数有$n(n-1)$ - k,即为不合理。
class Solution {
public:
bool isvaild(vector<int>& nums, int dis, int k)
{
int n = nums.size()
long long int count = 0;
int i = 0, j = 0;
while (i < n || j < n)
{
while (j < n && nums[j] - nums[i] <= dis) j++;
count += j - i - 1;
i++;
}
return count >= k;
};
int solve(vector<int>& nums, int k) {
int n = nums.size();
k++;
sort(nums.begin(), nums.end());
int l = 0, r = nums[n - 1] - nums[0];
while(l < r)
{
int mid = l + (r - l) / 2;
int count = 0, left = 0;
if(isvaild(nums, mid, k)) r = mid;
else l = mid + 1;
}
return l;
}
时间复杂度:O(nlogn)
空间复杂度:O(1)
排序
class Solution:
def solve(self, nums, k):
distances = []
for m in range(len(nums)-1):
for n in range(m+1, len(nums)):
distances.append(abs(nums[n] - nums[m]))
return sorted(distances)[k-1]
见代码注释:
var smallestDistancePair = function(nums, k) {
nums.sort((a , b) => a - b);
const check = (nums , diff , k) => {
// sliding window
// 计数 距离对 小于等于 diff 的 pairs 数量
let count = 0;
let j = 0;
for(let i = 1 ; i < nums.length ; ++i) {
// j = 0
// 无需复位 j ,因为 数组已经单调递增 若 nums[i] - nums[0] 不满足 <= diff
// nums[i+1] - nums[0] 一定不满足
while(nums[i] - nums[j] > diff) ++j;
// 由于数组有序 所以 i - j 就是当前轮满足的pair数
count += i - j;
}
return count >= k;
}
let l = 0;
let r = nums[nums.length - 1] - nums[0];
let mid;
while(l < r) {
mid = l + ((r - l) >> 1);
if(check(nums , mid , k)) {
r = mid;
} else {
l = mid + 1;
}
}
return l;
};
时间复杂度: O(nlogn)
额外空间复杂度: O(1)
二分
, 双指针
, 滑动窗口
int solve(vector<int>& nums, int k) {
int n = nums.size();
std::vector<int> results;
for (int i = 0; i < n-1;i++)
{
for (int j = i + 1; j < n;j++)
{
int d = nums[i] - nums[j];
results.push_back(abs(d));
}
}
sort(results.begin(), results.end());
return results[k];
}
复杂度分析
时间复杂度:O(n*n)
空间复杂度:O(n)
二分
int count_not_greater(vector<int>a,int diff)
{
int ans=0,len=a.size();
int i=0;
for(int j=1;j<len;j++)
{
while(a[j]-a[i]>diff)
i++;
ans+=(j-i);
}
return ans;
}
int solve(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
int l=0,r=nums.back()-nums[0];
while(l<=r)
{
int mid=l+(r-l)/2;
int t=count_not_greater(nums,mid);
if(t>k)
r=mid-1;
else
l=mid+1;
}
return l;
}
复杂度分析
class Solution:
def solve(self, nums, k):
nums_sort=sorted(nums)
ans=[]
def count(diff):
i=ans=0
for j in range(1,len(nums)):
while nums[j]-nums[i]>diff:
i+=1
ans+=j-i
return ans
l=0
r=nums[-1]-num[0]
k+=1
while l <= r:
mid = (l + r) // 2
if count(mid) >= k:
r = mid - 1
else:
l = mid + 1
return l
经过提点,我终于知道题目是个啥意思了。就是在返回的数组 abs(x-y)中找出 k 个小的元素。拿例子来说就是,k=3,那么 2 就是第三小的数
class Solution {
solve(nums = [], k) {
nums.sort()
const n = nums.length
k += 1
let start = 0
let end = nums[n - 1] - nums[0] // 这里之前没想到,不过用笔画下就知道了。假设nums为[1,2,5,10],你想想r是不是nums[n-1]-nums[0]
while (start <= end) {
let mid = start + (end - start) >> 1;
if (this.findpairs(nums, mid) >= k) {
end = mid - 1;
} else {
start = mid + 1;
}
}
return start;
}
findpairs(nums, val) {
const N = nums.length
let count = 0;
let i = 0, j = 0;
while (i < N || j < N) {
while (j < N && nums[j] - nums[i] <= val) {
j++;
}
count += j - i - 1;
i++;
}
return count;
}
}
822. Kth-Pair-Distance
入选理由
暂无
题目地址
https://binarysearch.com/problems/Kth-Pair-Distance
前置知识
题目描述
Constraints
n ≤ 100,000 where n is the length of nums Example 1 Input nums = [1, 5, 3, 2] k = 3 Output 2 Explanation Here are all the pair distances:
abs(1 - 5) = 4 abs(1 - 3) = 2 abs(1 - 2) = 1 abs(5 - 3) = 2 abs(5 - 2) = 3 abs(3 - 2) = 1 Sorted in ascending order we have [1, 1, 2, 2, 3, 4].