携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第25天,点击查看活动详情
给定一个 排序好 的数组 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]
排序
首先将数组 按照「更接近」的定义进行排序,如果 比 更接近 ,那么 将排在 前面。排序完成之后, 个最接近的元素就是数组 的前 个元素,将这 个元素从小到大进行排序后,直接返回。
var findClosestElements = function(arr, k, x) {
const list = [...arr];
list.sort((a, b) => {
if (Math.abs(a - x) !== Math.abs(b - x)) {
return Math.abs(a - x) - Math.abs(b - x);
} else {
return a - b;
}
});
const ans = list.slice(0, k);
ans.sort((a, b) => a - b);
return ans;
};
二分查找 + 双指针
假设数组长度为 ,注意到数组 已经按照升序排序,我们可以将数组 分成两部分,前一部分所有元素 都小于 ,后一部分所有元素 [ 都大于等于 , 与 都可以通过二分查找获得。
和 指向的元素都是各自部分最接近 的元素,因此我们可以通过比较 和 指向的元素获取整体最接近 的元素。如果 ,那么将 减一,否则将 加一。相应地,如果 或 已经越界,那么不考虑对应部分的元素。
最后,区间 的元素就是我们所要获得的结果,返回答案既可。
var findClosestElements = function(arr, k, x) {
let right = binarySearch(arr, x);
let left = right - 1;
while (k-- > 0) {
if (left < 0) {
right++;
} else if (right >= arr.length) {
left--;
} else if (x - arr[left] <= arr[right] - x) {
left--;
} else {
right++;
}
}
const ans = [];
for (let i = left + 1; i < right; i++) {
ans.push(arr[i]);
}
return ans;
}
const binarySearch = (arr, x) => {
let low = 0, high = arr.length - 1;
while (low < high) {
const mid = low + Math.floor((high - low) / 2);
if (arr[mid] >= x) {
high = mid;
} else {
low = mid + 1;
}
}
return low;
}