「这是我参与2022首次更文挑战的第36天,活动详情查看:2022首次更文挑战」
给定一个 排序好 的数组 arr ,两个整数 k 和 x ,从数组中找到最靠近 x(两数之差最小)的 k 个数。返回的结果必须要是按升序排好的。
整数 a 比整数 b 更接近 x 需要满足:
|a - x| < |b - x|或者|a - x| == |b - x|且a < b
示例 1:
输入:arr = [1,2,3,4,5], k = 4, x = 3
输出:[1,2,3,4]
示例 2:
输入:arr = [1,2,3,4,5], k = 4, x = -1
输出:[1,2,3,4]
算法
直观地,我们可以将数组中的元素按照与目标 x 的差的绝对值排序,排好序后前 k 个元素就是我们需要的答案。
var findClosestElements = function (arr, k, x) {
arr.sort((a, b) => (Math.abs(a - x) - Math.abs(b - x) == 0 ? a - b : Math.abs(a - x) - Math.abs(b - x)))
console.log(arr);
return arr.splice(0, k).sort((a, b) => a - b)
};
二叉查找和双指针
原本的数组是有序的,所以我们可以像如下步骤利用这一特点。
-
如果目标
x小于等于有序数组的第一个元素,那么前k个元素就是答案。 -
类似的,如果目标
x大于等于有序数组的最后一个元素,那么最后k个元素就是答案。 -
其他情况,我们可以使用二分查找来找到恰好大于 x 一点点的元素的索引 index 。然后让 low 等于 index 左边 k-1 个位置的索引,high 等于 index 右边 k-1 个位置的索引。我们需要的 kkk 个数字肯定在范围 [index-k-1, index+k-1] 里面。所以我们可以根据以下规则缩小范围以得到答案。
- 如果
low小于0或者low对应的元素比high对应的元素更接近x,那么减小high索引。 - 如果
high大于最后一个元素的索引arr.size()-1或者它比起low对应的元素更接近x,那么增加low索引。 - 当且仅当 [low, high] 之间恰好有 k 个元素,循环终止,此时范围内的数就是答案。
var findClosestElements = function (arr, k, x) { let low = 0, high = arr.length - 1; while (low < high) { const mid = low + Math.floor((high - low) / 2); x - arr[mid] > arr[mid + k] - x ? low = mid + 1 : high = mid; } return arr.slice(low, low + k); }; - 如果