链接:https://leetcode.com/problems/find-k-closest-elements/description/
Given a sorted array, two integers k
and x
, find the k
closest elements to x
in the array. The result should also be sorted in ascending order. If there is a tie, the smaller elements are always preferred.
Example 1:
Input: [1,2,3,4,5], k=4, x=3 Output: [1,2,3,4]
Example 2:
Input: [1,2,3,4,5], k=4, x=-1 Output: [1,2,3,4]
Note:
- The value k is positive and will always be smaller than the length of the sorted array.
- Length of the given array is positive and will not exceed 104
- Absolute value of elements in the array and x will not exceed 104
方法一:
class Solution { public: vector<int> findClosestElements(vector<int>& arr, int k, int x) { vector<int> res = arr; while (res.size() > k) { int first = 0, last = res.size() - 1; if (x - res.front() <= res.back() - x) { res.pop_back(); } else { res.erase(res.begin()); } } return res; } };
下面这种解法是论坛上的高分解法,用到了二分搜索法。其实博主最开始用的方法并不是帖子中的这两个方法,虽然也是用的二分搜索法,但博主搜的是第一个不小于x的数,然后同时向左右两个方向遍历,每次取和x距离最小的数加入结果res中,直到取满k个为止。但是下面这种方法更加巧妙一些,二分法的判定条件做了一些改变,就可以直接找到要返回的k的数字的子数组的起始位置,感觉非常的神奇。每次比较的是mid位置和x的距离跟mid+k跟x的距离,以这两者的大小关系来确定二分法折半的方向,最后找到最近距离子数组的起始位置,参见代码如下:
方法二
class Solution { public: vector<int> findClosestElements(vector<int>& arr, int k, int x) { int left = 0, right = arr.size() - k; while (left < right) { int mid = left + (right - left) / 2; if (x - arr[mid] > arr[mid + k] - x) left = mid + 1; else right = mid; } return vector<int>(arr.begin() + left, arr.begin() + left + k); } };