携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第27天,点击查看活动详情
快乐周四,大家疯狂起来!!
找到K个最接近的元素
该题出自力扣的658题 —— 找到K个最接近的元素【中等题】,这道题难也不算特别难,一般字数越少的越困难
审题
给定一个 排序好 的数组 arr ,两个整数 k 和 x ,从数组中找到最靠近 x(两数之差最小)的 k 个数。返回的结果必须要是按升序排好的。
- 整数 a 比整数 b 更接近 x 需要满足:
- |a - x| < |b - x| 或者
- |a - x| == |b - x| 且 a < b
- 该题题意很简单,但往往简单的才是最繁琐的,给出一个排序好的数组,给出两个整数,要在数组中找到K个最靠近x的数
- 首先需要明确的是,x不一定存在于数组中,因此需要对二分进行改造
- 这边想到的解决方法是:二分 + 双指针
- 利用二分找到最接近的下标
- 找到最小的最大下标,然后左节点等于右节点减一
- 循环遍历 k个数,直到k 大于0
- 利用条件判断,判断边界值,如果左节点 小于0,或者右节点 大于数组的长度
- 以及题目上提及的满足条件
- 最后再次遍历左右节点的数组,返回列表
- 除了二分 + 双指针,还可以使用数组的排序
- 也就是改动数组排序的比较器,利用题目规则排序,再输出前K个数即可
编码
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
List<Integer> list = new ArrayList<>(k);
// 找到对应下标
int right = findIndex(arr,x);
int 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++;
}
}
//双指针
for (int j = left + 1; j < right; j++) {
list.add(arr[j]);
}
return list;
}
private int findIndex(int[] arr, int x) {
int l = 0,r = arr.length - 1;
while (r > l){
int mid = l +((r -l) >> 1);
if (x >= arr[mid]){
l = mid + 1;
}else if (x < arr[mid]){
r = mid;
}
}
return l;
}
}