题目
给定一个 排序好 的数组 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]
示例 2:
输入:arr = [1,2,3,4,5], k = 4, x = -1
输出:[1,2,3,4]
提示:
1 <= k <= arr.length1 <= arr.length <= 10^4arr按 升序 排列-10^4 <= arr[i], x <= 10^4
解题
方法一:排序
思路
首先把数组按照与 x 的距离越近越靠前的顺序排序,具体来说:
- 如果 相等,越小的越靠前。
- 否则 的值越小越靠前。
然后拿出 arr 中前 k 个元素组成一个新的数组后升序排序返回。
代码
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
sort(arr.begin(), arr.end(), [x](int& a, int& b) {
int diff_a = abs(a - x), diff_b = abs(b - x);
return diff_a == diff_b ? a < b : diff_a < diff_b;
});
sort(arr.begin(), arr.begin() + k);
return {arr.begin(), arr.begin() + k};
}
};
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
List<Integer> lst = new ArrayList<Integer>() {{
for (int num : arr) this.add(num);
}};
Collections.sort(lst, (a, b) -> {
int diffA = Math.abs(a - x), diffB = Math.abs(b - x);
return diffA == diffB ? a - b : diffA - diffB;
});
List<Integer> ans = lst.subList(0, k);
Collections.sort(ans);
return ans;
}
}
方法二:双指针
思路
反向思考,从排序好的数组 arr 中找到最靠近 x 的 k 个数就是**删除最远离 x 的 arr.length - k**个数。
维护两个指针(left, right)分别指向数组左右两边,如果左指针指向的数与 x 的差值比右指针指向的数与 x 的差值大,说明左边更远离 x 把左指针右移表示删除左边的一个数,反之把右指针左移。
最后返回 arr[left:right+1] (这里类似 python 的数组切片,表示 arr 中的 [left, right+1) 区间)。
代码
class Solution {
public:
vector<int> findClosestElements(vector<int>& arr, int k, int x) {
int excld = arr.size() - k;
auto left = arr.begin(), right = arr.end() - 1;
for (int i = 0; i < excld; ++i) {
if (x - *left > *right - x) ++left;
else --right;
}
return {left, right + 1};
}
};
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int left = 0, right = arr.length - 1;
int excld = arr.length - k;
while (excld-- > 0) {
if (x - arr[left] > arr[right] - x) ++left;
else --right;
}
List<Integer> ans = new ArrayList<>();
for (; left <= right; ++left) ans.add(arr[left]);
return ans;
}
}
评论区