「这是我参与2022首次更文挑战的第35天,活动详情查看: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]
提示:
1 <= k <= arr.length1 <= arr.length <= 104arr按 升序 排列-104 <= arr[i], x <= 104
解题思路
本题要求我们找到 k 个最接近目标值的元素,因为元素数量是给定的 k 个,而且输入数组是按升序排列的,所以我们可以初始化一个滑动窗口,长度为 k,计算窗口中每个元素与目标值 x 的差值和,然后扫描从头到尾移动这个窗口,找到差值和最小的窗口,则窗口中的元素就是我们要找的 k 个数。
因为输入数组是有序的,所以当窗口下一次移动的差值和大于当前窗口的差值和,则后续的窗口范围内的差值和都会大于当前窗口的差值和,所以此时可以停止移动,返回当前窗口中的元素。
又因为根据示例1可知,当两个窗口中元素的差值和相等的时候,优先选择前面的窗口,所以我们需要从数组末尾确定窗口,然后向前移动。
代码实现
var findClosestElements = function(arr, k, x) {
// 初始化窗口的左右边界下标
let r = arr.length-1,l = r-k+1,
// 初始化窗口内元素和目标值的差值
diff = 0;
// 计算窗口内元素和目标值的差值
for(let i = r;i>=l;i--) diff += Math.abs(arr[i]-x)
// 当窗口左边界没有到达下标 0 时,向左移动窗口
while(l>0){
// 计算窗口下次移动后的差值和
const nextDiff = diff-Math.abs(arr[r]-x)+Math.abs(arr[l-1]-x)
// 如果下次移动后窗口的差值和小于等于当前窗口的差值和
if(nextDiff<=diff){
// 移动窗口
l--;
r--;
// 更新当前窗口的差值和
diff = nextDiff;
}
// 否则说明找到了差值和最小的窗口,返回窗口中的元素
else return arr.slice(l,l+k)
}
// 如果可以一直移动到数组最左侧,则说明最左侧的窗口是差值最小的窗口,返回该窗口中的元素
return arr.slice(l,l+k)
}
至此我们就完成了 leetcode-658-找到 K 个最接近的元素
如有任何问题或建议,欢迎留言讨论!👏🏻👏🏻👏🏻