LeetCode破解之找到 K 个最接近的元素

126 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情

给定一个 排序好 的数组 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]

类似二分搜索的非二分搜索

二分先找到x的index,然后比较左右差值决定选哪个,共k次,试着写了下代码发现要考虑的边界细节好多,关键代码放注释里然后就算了吧。。。

看了大佬思路,不保留再存储,直接在arr中找到不符合条件的值删除(移动指针,也不是删除吧)虽然非二分但是数独也很快。这个解法几个注意点

首先,数组是已经排好序的,要求我们找最靠近x的k个数,
 * 1,如果x在数组存在,则x本身肯定是最靠近x的,然后根据k的大小从x的左右两边选数出来;
 * 2,如果x不在数组中,则找到x应该存在的位置,然后判断左右的元素谁小;

优化:优化后效率要区分数组数量远大于k和跟k差不多的情况

- 大于k一定程度要先二分找到最接近x的数字然后取左右包含该数字的各k个数缩小比较到剩下k个数
- 如果没有大于k一定的程度则二分查找消耗的时间比节省的时间要多可以直接从最左最右向下缩小到只剩下k个数
class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        List<Integer> res = new ArrayList<Integer>();
        int i = 0, j = arr.length - 1;
        int count = arr.length - k;

        while (count > 0) {
            if (x - arr[i] <= arr[j] - x)
                j--;
            else
                i++;
            count--;
        }

        for (int y = i; y <= j; y++) {
            res.add(arr[y]);
        }
        return res;
    }
}

注意

注意几个问题,为什么 r 初始值要 - k?为什么是 x - arr[m] > arr[m + k] - x?m+k 不会越界吗?

而且 x - arr[m] > arr[m + k] - x的含义是,x在arr[m..m+k]中点偏右边位置。因为要找到中点最逼近x的位置,因此left = mid + 1(右移)。

我感觉这道题出的不好。 1.题目没有明确说数组是升序的,只说了是排序的,但实际上从测试用例看,默认是升序的。 2.二分并没有比排序快出多少来。但二分的复杂度超高,性价比不高,没有体现出二分的优越性。