乐趣区

关于后端:719-找出第-K-小的数对距离困难

题目形容

这是 LeetCode 上的 719. 找出第 K 小的数对间隔 ,难度为 艰难

Tag :「双指针」、「二分」

数对 $(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 <= 10^4$
  • $0 <= nums[i] <= 10^6$
  • $1 <= k <= n \times (n – 1) / 2$

二分 + 双指针

依据题意,因为对间隔定义应用的是绝对值,因而从原数组中找数对 $(i, j)$,等价于在排序数组中找数对 $(i, j)$。

同时因为 $k$ 的范畴为 $n^2$,因而咱们不能应用复杂度为 $O(k\log{n})$ 的「多路归并」做法来做。

利用数据范畴 $0 <= nums[i] <= 10^6$,咱们晓得间隔值域范畴为 $[0, 10^6]$,假如所能造成的间隔序列为 $A = a_1, a_2, … ,a_m$,此时在以第 $k$ 小的间隔值为宰割点的数轴上,具备「二段性」,记这第 $k$ 小的间隔值为 $a_k$:

  • 处于 $a_k$ 右侧的所有地位 $a_i$(蕴含 $a_k$)必然满足「序列 $A$ 中值小于等于 $a_i$ 的数不少于 $k$ 个」;
  • 处于 $a_k$ 左侧的所有地位 $a_i$(不蕴含 $a_k$)不肯定满足「序列 $A$ 中值小于等于 $a_i$ 的数不少于 $k$ 个」(当且仅当 $a_k$ 在序列 $A$ 中不反复,或 $a_k$ 恰好是间断段距离值中的左端点时,必然不满足)。

因而这实质上是一个满足 1? 个性(而不是 10 个性)的问题,咱们能够应用「二分」来找到 $a_k$ 值。

假如以后咱们二分到的值是 $x$,利用咱们排序好的 nums,咱们并不需要真正的构建出序列 $A$,即可统计值小于等于 $x$ 的数量:枚举左端点 $i$,每次找第一个不满足条件的右端点 $j$(因为 $j$ 是第一个不满足条件的值,因而非法右端点范畴为 $[i + 1, j – 1]$,共 $j – i – 1$ 个),利用 nums 有序,并且所有 $nums[i]$ 均为负数,可知 $j$ 会随着 $i$ 增大而逐渐增大,即这部分利用「双指针」可实现 $O(n)$ 复杂度。

代码:

class Solution {public int smallestDistancePair(int[] nums, int k) {Arrays.sort(nums);
        int l = 0, r = (int)1e6;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(nums, mid) >= k) r = mid;
            else l = mid + 1;
        }
        return r;
    }
    int check(int[] nums, int x) {
        int n = nums.length, ans = 0;
        for (int i = 0, j = 1; i < n; i++) {while (j < n && nums[j] - nums[i] <= x) j++;
            ans += j - i - 1;
        }
        return ans;
    }
}
  • 工夫复杂度:排序的复杂度为 $O(n\log{n})$,二分答案复杂度为 $O(n\log{m})$,其中 $m = 1e6$ 为间隔值域。整体复杂度为 $O(n\log{m})$
  • 空间复杂度:$O(\log{n})$

最初

这是咱们「刷穿 LeetCode」系列文章的第 No.719 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,局部是有锁题,咱们将先把所有不带锁的题目刷完。

在这个系列文章外面,除了解说解题思路以外,还会尽可能给出最为简洁的代码。如果波及通解还会相应的代码模板。

为了不便各位同学可能电脑上进行调试和提交代码,我建设了相干的仓库:https://github.com/SharingSou…。

在仓库地址里,你能够看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其余优选题解。

本文由 mdnice 多平台公布

退出移动版