题目
https://leetcode-cn.com/problems/find-k-closest-elements/
双指针
数组是排序的,使用双指针指向数组两端,如果一端离x更远就排除该指针指向的元素,如果一样远,根据题意排除右指针指向的元素
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int left = 0, right = arr.length - 1;
while (right - left != k - 1) {
if (Math.abs(arr[left] - x) > Math.abs(arr[right] - x)) {
left++;
} else {
right--;
}
}
List<Integer> ans = new ArrayList<>();
for (int i = left; i <= right; i++) {
ans.add(arr[i]);
}
return ans;
}
}
二分查找
思路:
查找最优区间的左边界,size
为arr
的长度, 由于要保证区间内有k
个元素所以,搜索范围为[0, size - k]
, left = 0, right = size - k
。
以中值mid
为左边界开辟一个长度为k+1
的区间[mid, mid + k]
对于 x 分情况讨论
-
x 在区间
[mid, mid + k]
外- x在
[mid, mid + k]
左边,则需要使整个区间向左移动, 所以right = mid
- x在
[mid, mid + k]
右边, 则整个区间需要向右移动,所以left = mid + 1
- x在
-
x 在区间
[mid, mid + k]
内- x在区间中间,或者x更靠近
arr[mid]
,整个区间需要向左移动,right = mid
- x更接近
arr[mid + k]
,整个区间需要向右移动,left = mid + 1
- x在区间中间,或者x更靠近
综上情况1.1 和 2.1、1.2 和 2.2 可以合并,也就是下面这段代码
if (x - arr[mid] > arr[mid + k] - x) {
left = mid + 1;
} else {
right = mid;
}
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int size = arr.length;
int left = 0;
int right = 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;
}
}
List<Integer>ans = new ArrayList<>();
for (int i = left;i < k + left; i++) {
ans.add(arr[i]);
}
return ans;
}
}