Find K-th Smallest Pair Distance

Question: 请添加图片描述

思路

这个题又一次刷新我对binary search 和 sliding window的三观…
没想到还能这么用

我们要找第k小的difference. 可以用heap 把所有的pair都推进去. 说实话这个方法还挺不错的. 就是先把array sort之后把每相邻的一对(index) 都push到heap里
然后因为假设我们push的一对index是{i,j} 然后num[j] >= num[I]
其实要找difference 的话. 其实就是算num[j] - num[I]. 接着要找出所有和num[I]的pair. 就是每次pop出来之后,再push进去{i, j+1}
这样就能保证heap可以涵盖所有的pair.
其实就是相当于一个double forloop 找所有pair
一个道理

for(int i = 0;i < n; ++i){
	for(int j = i+1;j < n; ++j){
	}
}

但是! 这个方法会time out. 虽然是O((N+K)logN) K是我们要pop k 次heap. N是最开始把n个pair先push进去

那么接下来. nb的方法! binary search + slinding window
binary search 最近我看见了好多题, md
就是binary search试验答案… 因为我们这个题是可以知晓最大difference (arry最后一个num - array第一个的num)和 最小difference(0).
所以就每次用binary search 的思维, 一个答案一个答案试验.
然后我们可以试验, 那具体过程怎么检查呢?
sliding window…

我感觉很多题是要么binary search 要么sliding window, 这俩结合的题一定是hard
怎么sliding window呢. 就是 先假设binary search 选的答案 = mid

我们从nums 开头开始移动我们的window. 如果nums[right] - nums[left] <= mid
那我们就移动我们的right window. 并且 count += right-left; count是我们的total count of pairs that difference <= mid
然后我们选的这个windows. [left, right] 如果nums[right] - nums[left] <= mid, 那就说明在[left, right] 这个区间里, 任意两对的difference 都小于mid. 因为nums[right] - nums[left] 就是这对儿的最大difference嘛. 那么我们就可以随着windows的增长, 每次直接加所有满足条件的pairs的数量
举个例子
每次right + 1. 就是windows+1. 那这个时候如果nums[right+1] - nums[left] 还满足条件, 那我们就计算这个right+1给我们的windows 增加了多少新的pairs就行了. 新组成的pairs就是nums[right+1] 和前面所有的num 一直到nums[left] 的组合. 就是(right+1) - left 个新增的pair. 那我们就count += right(+1之后的)-left 就好了
如果nums[right+1] = nums[left] 不满足条件了,没关系, shrink 我们的left window (left++).直到
nums[right + 1] - nums[left] <= mid. 然后这个时候, 因为最新的right+1不能和原先的left组成pair了. 只能从最新的left开始组成pair. 但其实也还是right - left 个. 我们的公式没问题.

其实简单来说, 这个sliding window就是通过一个for loop. 把每个nums[I] 都当作最大的, 找它能够组成所有满足条件的pairs.

然后可能confused的是, 如果有nums[j] 和 nums[I] 组成pair呢? I < j. 那算nums[I]的时候是没把j加进来的. 这个也是对的. 等到windows 走到j的时候,它自然会把(nums[j] -nums[I]) 这一对儿也加上. 然后我们也是正好不要重复. 所以没问题!!

class Solution {
    public int smallestDistancePair(int[] nums, int k) {
        Arrays.sort(nums);
        int low = 0;
        int high = nums[nums.length-1] - nums[0];
        
        while(low < high){
            int difference = (high + low) >> 1;
            if(check(nums, k, difference)){
                high = difference;
            } else{
                low = difference+1;
            }
        }
        
        return high;
    }
    
    public boolean check(int[] nums, int k, int difference){
        int count = 0;
        int left = 0;
        for(int i = 1;i < nums.length; ++i){
            while(nums[i] - nums[left] > difference) left++;
            count += i - left;
        }
        
        if(count >= k) return true;
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值