题目描述
给定一个排序好的数组 arr
,两个整数 k
和 x
,从数组中找到最靠近 x
(两数之差最小)的 k
个数。返回的结果必须要是按升序排好的。
整数 a
比整数 b
更接近 x
需要满足:
|a - x| < |b - x|
或者|a - x| == |b - x|
且a < b
样例
输入:arr = [1,2,3,4,5], k = 4, x = 3
输出:[1,2,3,4]
输入:arr = [1,2,3,4,5], k = 4, x = -1
输出:[1,2,3,4]
限制
1 <= k <= arr.length
1 <= arr.length <= 10^4
- 数组里的每个元素与
x
的绝对值不超过10^4
算法
(二分,双指针) O(logn+k)
- 使用二分,找到第一个大于等于 x 的位置 pr,若不存在则为 pr=n,然后令 pl=pr−1。
- 然后开始向两侧扩展 pl 和 pr,判断 arr(pl) 和 arr(pr) 谁更接近 x,移动 pl 或者 pr,直到找满 k 个数字为止。
时间复杂度
- 二分的时间复杂度为 O(logn),寻找答案的时间复杂度为 O(k),故总时间复杂度为 O(logn+k)。
C++ 代码
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
const int n = arr.size();
vector<int> ans(k);
int l = 0, r = n;
while (l < r) {
int mid = (l + r) >> 1;
if (x <= arr[mid]) r = mid;
else l = mid + 1;
}
int pl = l - 1, pr = l;
while (k--) {
if (pl == -1) pr++;
else if (pr == n) pl--;
else {
if (x - arr[pl] <= arr[pr] - x) pl--;
else pr++;
}
}
for (int i = pl + 1, j = 0; i < pr; i++, j++)
ans[j] = arr[i];
return ans;
}
};
while (r - l - 1 < k && (l >= 0 || r < n)) 没看懂是什么意思
题解已修正
其实这就是保证只取 k 个元素。