算法小知识-----8.25-----找到K个最接近的元素

75 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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;
    }
}

image.png