nice-people-frontend-community / nice-js-leetcode

好青年 | leetcode 今日事今日毕(✅ Solutions to LeetCode by JavaScript, 100% test coverage, runtime beats 100% / LeetCode 题解 / GitHub Actions集成LeetCode每日一题至issues)

Home Page:https://nice-people-frontend-community.github.io/nice-js-leetcode/

Repository from Github https://github.comnice-people-frontend-community/nice-js-leetcodeRepository from Github https://github.comnice-people-frontend-community/nice-js-leetcode

[2022-06-15]719. 找出第 K 小的数对距离👋数组👋双指针👋二分查找👋排序

webVueBlog opened this issue · comments

题目链接: https://leetcode-cn.com/problems/find-k-th-smallest-pair-distance

难度: Hard
标签: 数组 双指针 二分查找 排序

719. 找出第 K 小的数对距离

Description

Difficulty: 困难

Related Topics: 数组, 双指针, 二分查找, 排序

数对 (a,b) 由整数 ab 组成,其数对距离定义为 ab 的绝对差值。

给你一个整数数组 nums 和一个整数 k ,数对由 nums[i]nums[j] 组成且满足 0 <= i < j < nums.length 。返回 所有数对距离中k 小的数对距离。

示例 1:

输入:nums = [1,3,1], k = 1
输出:0
解释:数对和对应的距离如下:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
距离第 1 小的数对是 (1,1) ,距离为 0 。

示例 2:

输入:nums = [1,1,1], k = 2
输出:0

示例 3:

输入:nums = [1,6,1], k = 3
输出:5

提示:

  • n == nums.length
  • 2 <= n <= 104
  • 0 <= nums[i] <= 106
  • 1 <= k <= n * (n - 1) / 2

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var smallestDistancePair = function(nums, k) {

};

解答:排序 + 二分查找 + 双指针

给定距离 mid,计算所有距离小于等于mid 的数对数目 cnt 可以使用双指针:初始左端点 i = 0,我们从小到大枚举所有数对的右端点 j,移动左端点直到 nums[j]−nums[i]≤mid,那么右端点为 j 且距离小于等于 mid 的数对数目为 j - i,计算这些数目之和。

var smallestDistancePair = function(nums, k) {
    nums.sort((a, b) => a - b);
    let n = nums.length, left = 0, right = nums[n - 1] - nums[0];
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        let cnt = 0;
        for (let i = 0, j = 0; j < n; j++) {
            while (nums[j] - nums[i] > mid) {
                i++;
            }
            cnt += j - i;
        }
        if (cnt >= k) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

719. 找出第 K 小的数对距离

Description

Difficulty: 困难

Related Topics: 数组, 双指针, 二分查找, 排序

数对 (a,b) 由整数 ab 组成,其数对距离定义为 ab 的绝对差值。

给你一个整数数组 nums 和一个整数 k ,数对由 nums[i]nums[j] 组成且满足 0 <= i < j < nums.length 。返回 所有数对距离中k 小的数对距离。

示例 1:

输入:nums = [1,3,1], k = 1
输出:0
解释:数对和对应的距离如下:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
距离第 1 小的数对是 (1,1) ,距离为 0 。

示例 2:

输入:nums = [1,1,1], k = 2
输出:0

示例 3:

输入:nums = [1,6,1], k = 3
输出:5

提示:

  • n == nums.length
  • 2 <= n <= 104
  • 0 <= nums[i] <= 106
  • 1 <= k <= n * (n - 1) / 2

Solution

Language: JavaScript

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var smallestDistancePair = function(nums, k) {
    nums.sort((a, b) => a - b);
    const n = nums.length;
    let left = 0;
    let right = nums[n - 1] - nums[0];  // 距离差的范围

    while (left < right) {
        const mid = (left + right) >>> 1;
        if (countLessThenK(mid, k, nums)) left = mid + 1;
        else right = mid;
    }

    return left;
};

const countLessThenK = (mid, k, nums) => {
    let [count, start] = [0, 0];
    
    for (let i = 1; i < nums.length; i++) {  // start为起点, i 为终点,找出距离差小于mid的数量
        while (nums[i] - nums[start] > mid) start++; 

        count += i - start; // 区间 [start, i] 以内的所有的数的距离差都小于 mid , 所以总数是 i - start
    }

    return count < k;
}